编程技巧之表格驱动编程

/* 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好,扩展性极好。

 

编程技巧之表格驱动编程,布布扣,bubuko.com

时间: 2024-11-03 20:57:06

编程技巧之表格驱动编程的相关文章

驱动编程思想之初体验 --------------- 嵌入式linux驱动开发之点亮LED

这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的住,不然真像一些人说的,学了一年嵌入式感觉还没找到门. 不能再扯了,涉及到linux的驱动开发知识面灰常广,再扯文章就会变得灰常长.首先还是回到led驱动的本身上,自从linux被移植到arm上后,做驱动开发的硬件知识要求有所降低,很多都回归到了软件上,这是系统编程的一大特点,当然 ,也不排除有很多

嵌入式linux驱动开发之点亮led未遂(驱动编程思想之初体验)

有了上两篇文章的基础,我们就可以开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的住,不然真像一些人说的,学了一年嵌入式感觉还没找到门. 另外实践很重要,一年多以前就知道了arm,那时整天用单片机的思维去yy着arm,直到前段时间弄来一块arm板,烧上linux系统后才知道,坑呀!根本不是那回事,所以实践是学习计算机类最重要的基本素质,如果整天看书,那基本上

单片机应用编程技巧问答

1. C语言和汇编语言在开发单片机时各有哪些优缺点? 答:汇编语言是一种用文字助记符来表示机器指令的符号语言,是最接近机器码的一种语言.其主要优点是占用资源少.程序执行效率高.但是不同的CPU,其汇编语言可能有所差异,所以不易移植. C语言是一种结构化的高级语言.其优点是可读性好,移植容易,是普遍使用的一种计算机语言.缺点是占用资源较多,执行效率没有汇编高. 对于目前普遍使用的RISC架构的8bit MCU来说,其内部ROM.RAM.STACK等资源都有限,如果使用C语言编写,一条C语言指令编译

Linux Shell常用技巧(十二) Shell编程

Linux Shell常用技巧(十二) Shell编程 二十三. Bash Shell编程:  1.  读取用户变量:    read命令是用于从终端或者文件中读取输入的内建命令,read命令读取整行输入,每行末尾的换行符不被读入.在read命令后面,如果没有指定变量名,读取的数据将被自动赋值给特定的变量REPLY.下面的列表给出了read命令的常用方式: 命令格式 描述 read answer 从标准输入读取输入并赋值给变量answer. read first last 从标准输入读取输入到第

VC/MFC 编程技巧大总结

1 toolbar默认位图左上角那个点的颜色是透明色,不喜欢的话可以自己改. 2 VC++中 WM_QUERYENDSESSION WM_ENDSESSION 为系统关机消息. 3 Java学习书推荐:<java编程思想> 4 在VC下执行DOS命令 a. system("md c:\\12"); b. WinExec("Cmd.exe /C md c:\\12", SW_HIDE); c. ShellExecute ShellExecute(NULL,

(转)Windows驱动编程基础教程

版权声明 本书是免费电子书. 作者保留一切权利.但在保证本书完整性(包括版权声明.前言.正文内容.后记.以及作者的信息),并不增删.改变其中任何文字内容的前提下,欢迎任何读者 以任何形式(包括各种格式的文档)复制和转载本书.同时不限制利用此书赢利的行为(如收费注册下载,或者出售光盘或打印版本).不满足此前提的任何转载. 复制.赢利行为则是侵犯版权的行为. 发现本书的错漏之处,请联系作者.请不要修改本文中任何内容,不经过作者的同意发布修改后的版本. 作者信息 作者网名楚狂人.真名谭文.在上海从事W

第6章 Android驱动编程

第6章  Android驱动编程 通过介绍本章设备驱动.字符设备驱动编程.GPIO驱动程序实例和4*4扫描键盘驱动等内容,熟练掌握了Android驱动编程.Android内核内核模块编程中包括设备驱动和内核模块.模块相关命令.Android内核内核模块编程和内核模块实例程序.Android内核中采用可加载的模块化设计,一般情况下编译的Android内核是支持可插入式模块的,也就是将最基本的核心代码编译在内核中.模块相关命令中lsmod列出了当前系统中加载的模块,rmmood用于当前模块卸载,in

14、字符驱动编程模型

字符驱动编程模型 上面就是内核的cdev的结构.他只有6个成员.有一些是内核自己回去用的,有一些是我们程序员要去用的.例如:count,表明设备有几个可以用.例如,我的开发板支持三个串口.所以count=3.还有设备号:查看设备文件: 我们从前面知道,我们是通过字符设备文件来访问我们的字符设备驱动的.两者是通过主设备号来建立联系的. 一个主设备好可以对应多个此设备号.他们是同一类型的设备.驱动程序就是通过次设备号来区分是串口1还是串口2的 设备号的操作 设备号分配 设备号-注销 这是一个很重要的

Linux内核驱动编程

Linux内核驱动编程 2015-02-12 驱动程序基础的东西这儿就不罗嗦了,百度上有更好的资料,此处我们只是注重实际用处. 下面我们开始写程序: 一.初步helloword程序 首先是来一个简单的hello. hello.c代码: 1 /****************************** 2 3 the first program 4 5 Hello World! 6 7 ******************************/ 8 9 #include <linux/mod