惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 叶小钗
S
Security @ Cisco Blogs
月光博客
月光博客
V
Vulnerabilities – Threatpost
The Hacker News
The Hacker News
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Cisco Talos Blog
Cisco Talos Blog
J
Java Code Geeks
Scott Helme
Scott Helme
S
Schneier on Security
腾讯CDC
博客园 - 司徒正美
L
Lohrmann on Cybersecurity
Latest news
Latest news
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
有赞技术团队
有赞技术团队
AWS News Blog
AWS News Blog
V
Visual Studio Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Hugging Face - Blog
Hugging Face - Blog
爱范儿
爱范儿
小众软件
小众软件
博客园 - Franky
Attack and Defense Labs
Attack and Defense Labs
美团技术团队
IT之家
IT之家
TaoSecurity Blog
TaoSecurity Blog
SecWiki News
SecWiki News
P
Proofpoint News Feed
阮一峰的网络日志
阮一峰的网络日志
博客园_首页
PCI Perspectives
PCI Perspectives
量子位
T
Threat Research - Cisco Blogs
酷 壳 – CoolShell
酷 壳 – CoolShell
Last Week in AI
Last Week in AI
Cyberwarzone
Cyberwarzone
The Cloudflare Blog
博客园 - 三生石上(FineUI控件)
L
LINUX DO - 最新话题
Forbes - Security
Forbes - Security
罗磊的独立博客
宝玉的分享
宝玉的分享
Simon Willison's Weblog
Simon Willison's Weblog
雷峰网
雷峰网
www.infosecurity-magazine.com
www.infosecurity-magazine.com
人人都是产品经理
人人都是产品经理
N
News and Events Feed by Topic

浮生笔记

时机的重要性 回答dayu博客的几个问题 学会做选择 我理想的城市 如何选择一个适合的城市 马来西亚游记 回首2023,展望2024 从ChatGPT聊起 菲律宾旅游攻略笔记 深圳游记 香港游记 怎样赚钱----我理解的商业模式 用户界面与跨平台 使用telnet通过IMAP协议读取QQ邮箱 信息成本-----从ChatGPT到情报学 买断制到订阅制----兼谈消费频次 我眼中的CSDN 迁移博客内容到静态博客 Hugo使用Jane主题支持搜索实现 C语言和Lua的相互调用示例代码 从放逐之城看经济学 不同产业的分析 回首2021,展望2022 游戏中的经济学 Windows获取网络地址、子网掩码等 -fsanitize=address 参数作用 C++ 编译器支持标准判断 C++ 编译器支持标准判断 VS Code的golang开发配置 之 代码提示 二叉树遍历的非递归算法的实现 我的Chrome插件 golang 获取get参数 关于写代码的几个看法 golang编程之我见 Linux 网络编程之 Select 构建之法读书笔记 (1) 友情链接 Effective Morden C++ 读书笔记(3) 二进制协议 vs 文本协议 从重构到重写 asio制作使用ssl通信的证书 gdb 7.11 Linux 获取网卡信息 《构建之法》读后感 由买冰箱想到的 2014年年终总结 聊聊我对写好程序的认识 经验搜索排名---google已经做过类似的了(我想多了) 有关编程语言的认识
编程技巧之表格驱动编程
DennisThink · 2014-07-27 · via 浮生笔记
/* Image format-dependent operations. */

typedef struct {

	jas_image_t *(*decode)(jas_stream_t *in, char *opts);
	/* Decode image data from a stream. */

	int (*encode)(jas_image_t *image, jas_stream_t *out, char *opts);
	/* Encode image data to a stream. */

	int (*validate)(jas_stream_t *in);
	/* Determine if stream data is in a particular format. */

} jas_image_fmtops_t;

/* Image format information. */

typedef struct {

	int id;
	/* The ID for this format. */

	char *name;
	/* The name by which this format is identified. */

	char *ext;
	/* The file name extension associated with this format. */

	char *desc;
	/* A brief description of the format. */

	jas_image_fmtops_t ops;
	/* The operations for this format. */

} jas_image_fmtinfo_t;

这段代码是从jasper的源代码中摘抄出来的,jas_image_fmtops_t 这个结构体定义了三个函数指针,是对图像的基本操作。s_image_fmtinfo_t 描述了一个图片的最基本的属性。包括id号,格式定义等。刚刚开始的时候我不明白为什么id不定义成枚举类型,而要定义成int。当我看到下面的代码的时候,我知道了。

我们接着看下面的代码

jas_init

/* Initialize the image format table. */
int jas_init()
{
	jas_image_fmtops_t fmtops;
	int fmtid;

	fmtid = 0;

#if !defined(EXCLUDE_MIF_SUPPORT)
	fmtops.decode = mif_decode;
	fmtops.encode = mif_encode;
	fmtops.validate = mif_validate;
	jas_image_addfmt(fmtid, "mif", "mif", "My Image Format (MIF)", &fmtops);
	++fmtid;
#endif

#if !defined(EXCLUDE_PNM_SUPPORT)
	fmtops.decode = pnm_decode;
	fmtops.encode = pnm_encode;
	fmtops.validate = pnm_validate;
	jas_image_addfmt(fmtid, "pnm", "pnm", "Portable Graymap/Pixmap (PNM)",
	  &fmtops);
	jas_image_addfmt(fmtid, "pnm", "pgm", "Portable Graymap/Pixmap (PNM)",
	  &fmtops);
	jas_image_addfmt(fmtid, "pnm", "ppm", "Portable Graymap/Pixmap (PNM)",
	  &fmtops);
	++fmtid;
#endif

#if !defined(EXCLUDE_BMP_SUPPORT)
	fmtops.decode = bmp_decode;
	fmtops.encode = bmp_encode;
	fmtops.validate = bmp_validate;
	jas_image_addfmt(fmtid, "bmp", "bmp", "Microsoft Bitmap (BMP)", &fmtops);
	++fmtid;
#endif

#if !defined(EXCLUDE_RAS_SUPPORT)
	fmtops.decode = ras_decode;
	fmtops.encode = ras_encode;
	fmtops.validate = ras_validate;
	jas_image_addfmt(fmtid, "ras", "ras", "Sun Rasterfile (RAS)", &fmtops);
	++fmtid;
#endif

#if !defined(EXCLUDE_JP2_SUPPORT)
	fmtops.decode = jp2_decode;
	fmtops.encode = jp2_encode;
	fmtops.validate = jp2_validate;
	jas_image_addfmt(fmtid, "jp2", "jp2",
	  "JPEG-2000 JP2 File Format Syntax (ISO/IEC 15444-1)", &fmtops);
	++fmtid;
	fmtops.decode = jpc_decode;
	fmtops.encode = jpc_encode;
	fmtops.validate = jpc_validate;
	jas_image_addfmt(fmtid, "jpc", "jpc",
	  "JPEG-2000 Code Stream Syntax (ISO/IEC 15444-1)", &fmtops);
	++fmtid;
#endif

#if !defined(EXCLUDE_JPG_SUPPORT)
	fmtops.decode = jpg_decode;
	fmtops.encode = jpg_encode;
	fmtops.validate = jpg_validate;
	jas_image_addfmt(fmtid, "jpg", "jpg", "JPEG (ISO/IEC 10918-1)", &fmtops);
	++fmtid;
#endif

#if !defined(EXCLUDE_PGX_SUPPORT)
	fmtops.decode = pgx_decode;
	fmtops.encode = pgx_encode;
	fmtops.validate = pgx_validate;
	jas_image_addfmt(fmtid, "pgx", "pgx", "JPEG-2000 VM Format (PGX)", &fmtops);
	++fmtid;
#endif

	/* We must not register the JasPer library exit handler until after
	at least one memory allocation is performed.  This is desirable
	as it ensures that the JasPer exit handler is called before the
	debug memory allocator exit handler. */
	atexit(jas_cleanup);

	return 0;
}
  

int jas_image_addfmt(int id, char *name, char *ext, char *desc,
  jas_image_fmtops_t *ops)
{
	jas_image_fmtinfo_t *fmtinfo;
	assert(id >= 0 && name && ext && ops);
	if (jas_image_numfmts >= JAS_IMAGE_MAXFMTS) {
		return -1;
	}
	fmtinfo = &jas_image_fmtinfos[jas_image_numfmts];
	fmtinfo->id = id;
	if (!(fmtinfo->name = jas_strdup(name))) {
		return -1;
	}
	if (!(fmtinfo->ext = jas_strdup(ext))) {
		jas_free(fmtinfo->name);
		return -1;
	}
	if (!(fmtinfo->desc = jas_strdup(desc))) {
		jas_free(fmtinfo->name);
		jas_free(fmtinfo->ext);
		return -1;
	}
	fmtinfo->ops = *ops;
	++jas_image_numfmts;
	return 0;
}

jas_image_fmtinfos 是jas_image_fmtinfo_t类型的数组。

答案即将揭晓: 从上面的代码可以看出,作者使用了表格驱动编程。全局变量jas_image_fmtinfos 保存了所有支持的图片格式的全部信息。而每次要对某种格式进行添加或者删除的时候,只用修改jas_init的代码就可以了,而且格式的编号是动态的。每次进行使用的时候去该数组中查找就可以了。 下面看看使用的代码,这段函数是根据后缀名查询编号的。

int jas_image_fmtfromname(char *name)
int jas_image_fmtfromname(char *name)
{
	int i;
	char *ext;
	jas_image_fmtinfo_t *fmtinfo;
	/* Get the file name extension. */
	if (!(ext = strrchr(name, '.'))) {
		return -1;
	}
	++ext;
	/* Try to find a format that uses this extension. */	
	for (i = 0, fmtinfo = jas_image_fmtinfos; i < jas_image_numfmts; ++i,
	  ++fmtinfo) {
		/* Do we have a match? */
		if (!strcmp(ext, fmtinfo->ext)) {
			return fmtinfo->id;
		}
	}
	return -1;
}

  从上面的代码可以看出,每次查询后缀对应的格式的时候,去比较当前的后缀名和jas_image_fmtinfos 数组中对应的后缀名,来确定id好,扩展性极好。

文章作者 DennisThink

上次更新 2014-07-27

许可协议 CC BY-NC-ND 4.0