potracelib中文翻译 Potrace库应用程序接口

Potrace库应用程序接口
1.范围

Potrace库提供:
•描绘,即,将位图转换为矢量表示(贝塞尔曲线和直线段)。
不提供前端功能,如:
•位图准备(比如,从文件中读取位图,通过阈值分割、缩放、过滤灰度级图像等方式来准备位图,等)
不提供前端功能,如:
•矢量表示的后续处理(例如转换为PostScript或SVG的文件格式、缩放+旋转、量化等)。

2.数据描述
2.1位图
2.1.1坐标系

Potrace在笛卡尔坐标系中嵌入一个大小为w×h的位图,其中每个像素占用一个单位平方的空间。如图1所示,通过定位,使像素的角点(而不是其中心)位于具有整数坐标的点上。坐标系的原点位于位图的左下角。位图四个角的坐标为(0、0)、(0、H)、(W、H)和(W、0)。

图1. Potrace坐标系

有时需要提及一个特定的像素(而不是平面上的一个点)。pixel[i,j]指的是在Potrace坐标系中,角点具有坐标(i,j),(i,j+1),(i+1,j+1),(i+1,j)的像素。因此,pixel[i,j]是中心位于坐标(i+0.5,j+0.5)处的像素。为了避免混淆,我们在表示像素时使用方括号,在表示点时使用圆括号。

2.1.2位图表示

Potrace库potracelib.h中定义了位图的格式要求如下:

struct potrace_bitmap_s {
int w, h; /* width and height, in pixels */
int dy; /* scanline offset in words */
potrace_word *map; /* pixel data, dy*h words */
};
typedef struct potrace_bitmap_s  potrace_bitmap_t;

这里的potrace_word是potracelib.h中定义的无符号整数类型,长度通常等于本机机器字长度(即,32位体系结构中的32位长度)。在接下来的解释中,我们假设potrace_word类型长度为N位。
将尺寸为w×h的位图从下到上分割为h个水平扫描线,将每个扫描线从左到右分割为多个块,使每个块包含N个像素。将每个块存储为单个potrace_word,其中块的最左边像素对应于字的最高有效位,块的最右边像素对应于字的最低有效位。

“on”(或“black”或“foreground”)状态的像素由位值1表示。“off”(“white”或“background”)状态的像素由位值0表示。

如果扫描行中的位数不能被N整除,则用零将扫描行最右边的字填充在右边。
扫描线0(最下面的扫描线)的数据从map[0]开始。扫描线1的数据从map[dy]开始。扫描线2的数据从map[2*dy]开始,以此类推。需要注意的是,dy的取值可以是正的,也可以是负的,这取决于应用程序希望如何在内存中放置图像数据。

总之,坐标为[i,j]的像素可以通过以下C公式访问:

pixel(i,j) = ((map + j*dy)[i/N] & (1 << (N-1-i%N)) ? 1 : 0.
2.1.3举例

图2显示了一个大小为36×12的位图示例。阴影像素为“on”,白色像素为“off”。

图2. 简单的位图

图3显示了在potrace_bitmap_t数据结构中对这个位图可能的描述。请注意,数据按照从下到上和从左到右的方式存储在map数组中。

图3. 简单的位图表示。

2.1.4关于字节顺序的注意事项

请记住,将位图存储为word类型的数组,而不是字节类型的数组。虽然这种区别在big-endian体系结构上体现不出差异,但在little-endian体系结构(如基于Intel的体系结构)上却有显著差异。例如,在little-endian机器上将整数字0x1F80FC02作为字节数组访问时,字节会以反序的方式出现:0x02、0xFC、0x80、0x1F。因此,将位图从基于字节的格式转换为Potrace的基于word的格式时,必须特别小心。

2.1.5坐标独立性

作为Potrace的输出,矢量数据的坐标系与输入位图的坐标系(即图1中的坐标系)相同。原则上,应用程序是否将坐标原点放在图像的左下角或左上角无关紧要,只要它解释图像输出坐标的方式与解释输入坐标的方式相同。

但是,坐标系的反转会扰乱下文中矢量图像归约里“顺时针”和“逆时针”两个词的含义(见第2.2.5节),也会影响Potrace的转向策略的含义(见第2.3节)。因此,为了明确起见,我们假设坐标原点位于左下角。如果应用程序希望采用不同的约定,那么必须相应地进行补偿。

2.2矢量格式
2.2.1点

在Potrace中,使用potrace_dpoint_t类型的值表示欧几里德平面上的点(x,y)。

struct potrace_dpoint_s {
double x, y;
};
typedef struct potrace_dpoint_s potrace_dpoint_t;
2.2.2线段

在Potrace中,曲线由下述两类线段组成:

•贝塞尔曲线段。如图4(a)所示,贝塞尔曲线段通常由起点A、两个控制点U和W以及终点B给出。
•转角线段。如图4(b)所示,角段由起点A、顶点V和端点B给出。将角段绘制为两条直线:一条从A到V,一条从V到B。

在这里插入图片描述
图4. (a)贝塞尔曲线段。(b)转角线段。

2.2.3曲线

在Potrace中,曲线由一系列的线段组成,每一条线段的终点与下一条线段的起点重合。在Potrace中,所有的曲线都是闭合的,因此最后一条线段的终点也与第一条线段的起点重合。图5显示了一个由4条线段组成的曲线示例:3条贝塞尔曲线段和1条转角线段。为清楚起见,线段的起点和终点用圆点•标记。

在这里插入图片描述
图5. 由四条线段组成的闭合曲线。

将曲线表示为potrace_curve_t类型的值,定义如下:

struct potrace_curve_s {
int n; /* number of segments */
int *tag; /* array of segment types */
potrace_dpoint_t (*c)[3]; /* array of control points. */
};
typedef struct potrace_curve_s potrace_curve_t;

其中n≥1表示曲线中的线段数。对于i=0, …,n-1,tag[i]表示第i条线段的类型。对于贝塞尔曲线段,tag[i]是POTRACE_CURVETO类型,对于转角线段,tag[i]是POTRACE_CORNER类型。c是一个大小为n×3的数组,它通过以下方式保存曲线线段的控制点:

•如果第i段是贝塞尔曲线段,则c[i][0]=u和c[i][1]=w是该线段的两个控制点,c[i][2]=b是其终点。
•如果第i段是转角线段,则c[i][0]未使用,c[i][1]=v是该线段的顶点,c[i][2]=b是其端点。

注意,由于每条线段的起点A与前一条线段的终点B重合(并且第一条线段的起点A与最后一条线段的终点B重合),因此无需显式存储起点A。另外,请注意,无论线段的类型如何,第i段的终点都是c[i][2],第i段的起点都是c[i?I-1:N-1][2]。

因此,图5中的曲线由以下数据表示:

n = 4;
tag[0] = POTRACE_CURVETO;
c[0][0] = u0; c[0][1] = w0; c[0][2] = b0 = a1;
tag[1] = POTRACE_CURVETO;
c[1][0] = u1; c[1][1] = w1; c[1][2] = b1 = a2;
tag[2] = POTRACE_CURVETO;
c[2][0] = u2; c[2][1] = w2; c[2][2] = b2 = a3;
tag[3] = POTRACE_CORNER;
c[3][0] = unused; c[3][1] = v3; c[3][2] = b3 = a0;
2.2.4双矢量图像的边界分解

在Potrace中,如图6(a)所示的双(即黑白)矢量图像分解为一组闭合边界曲线,以蓝色和红色显示,并在图6(b)中标记为A-I。

在这里插入图片描述
图6:(a)矢量图像。(b)边界分解。

我们介绍一些术语。如果闭合曲线本身不相交,则它是简单的。每一条简单的闭合曲线,由它自己决定,将平面分为两个区域,分别称为曲线的内侧和外侧。如果C1和C2是简单的闭合曲线,那么在C1完全位于C2的内部的情况下,我们说C1包含在C2中,记为C1<C2。例如,在图6(b)中,曲线B-E包含在A中,而F-I不包含在A中。

在如图6所示的矢量图像分解中,如果C1<C2,则曲线C1是C2的子曲线且C1和C2之间没有另外的曲线C3(即,没有曲线C3使得C1<C3<C2)。在这种情况下,我们还将C1称为C2的父曲线。由于边界曲线不相交,每条曲线最多有一个父曲线。如果两条曲线都没有父曲线,或者有一个共同的父曲线,那么这两条曲线的关系就被称为兄弟。请注意,“子”关系自然地定义了曲线集上的树结构(更准确地说,它定义了“森林”,因为可以有多个根)。

例如,在图6(b)中,曲线A没有父曲线,有子曲线B和E。曲线E没有子曲线,曲线B有子曲线C和D。A和F是兄弟曲线,B和E是兄弟曲线,C和D是兄弟曲线。图6(b)中的曲线在“子”关系下形成以下森林:

在这里插入图片描述
如果曲线包围“前景”区域,我们可以指定曲线的符号为正;如果曲线包围“背景”区域(或“孔”),我们可以指定曲线的符号为负。例如,在图6(b)中,正曲线以蓝色显示,负曲线以红色显示。

由于前景和背景区域是交替出现的,因此曲线的符号也交替出现,即无父曲线总是正的,所有其它曲线的符号都与父曲线的符号相反。由此可见,在树结构中,在偶数层出现的曲线是正的,在奇数层出现的曲线是负的。尤其是,兄弟曲线的符号是一样的。

2.2.5矢量图的描述

在Potrace中,矢量图表示为potrace_path_t类型的零个或多个结构的链接集合,定义如下:

struct potrace_path_s {
int area; /* enclosed area */
int sign; /* ’+’ or ’-’ */
potrace_curve_t curve; /* vector data */
struct potrace_path_s *next; /* list structure */
struct potrace_path_s *childlist; /* tree structure */
struct potrace_path_s *sibling; /* tree structure */
struct potrace_privpath_s *priv; /* private state */
};
typedef struct potrace_path_s potrace_path_t;

每一个这样的结构都有一条曲线,并且这些结构通过next、childlist和sibling指针相互链接。

•sign字段保存曲线的符号(“+”或“-”的ASCII格式)。

•curve字段包含第2.2.3节所述的曲线矢量数据。Potrace还遵循正曲线逆时针运行和负曲线顺时针运行的惯例;这有助于在具有基于环绕数的“填充”规则的环境(如PostScript或PDF)中进行渲染。

•area字段给出了曲线所包围的面积的近似大小。(实际上,它是原始的未描述的“jaggy” 曲线的精确整数区域)。基于此,有些用户通过忽略第一次渲染过程中非常小的区域来提高交互式渲染的速度。另请参见下面第2.3节中的turdsize参数说明。

•priv字段由Potrace内部使用,应用程序无法访问。

•next字段用于将给定矢量图的所有曲线链接到链接列表中。每个成员通过其next字段指向下一个成员,列表的最后一个成员的next==null。列表元素的顺序并未指定,但保证满足以下限制:
(a)外部曲线出现在内部曲线之前,因此,如果C1<C2,则C2总是在C1之前的某个时间出现在链接列表中,并且
(b)每个正曲线之后都紧跟着其所有子曲线。

这两个约束使得用户通过简单地按顺序处理链接列表来呈现图像。约束(a)使得采用纯黑或纯白填充每条曲线成为可能,从而能够在早期曲线的部分上绘制后期曲线。约束(b)进一步允许用户在一次绘制操作中填充一条正曲线,减去其负子曲线,为每条负子曲线留下一个“孔”。

•childlist字段和sibling字段在一组曲线上定义一个森林结构,可以独立于链接列表结构使用。对于每一条曲线,childlist是指向其第一个孩子的指针,如果没有孩子,则为NULL。另外,sibling是指向下一个兄弟的指针,如果没有更多的兄弟,则为NULL。兄弟姐妹的相对顺序未指定。树结构的根节点始终与链接列表结构的根节点保持一致。
由零条曲线组成的图像表示为NULL指针。

2.2.6相交曲线

在上面的讨论中,我们假设了一组不相交的曲线,在实践中,可能会出现Potrace输出的曲线稍微相交的情况。因此,用户应仔细选择其渲染参数(例如,非零环绕数规则比奇数环绕数规则更可取),以避免出现不需要的瑕疵。

2.2.7举例

图6中的图可以用指针plist表示,其中A-I是potrace_path_t类型的结构,如下所示。我们没有显示area字段和curve字段。

potrace_path_t *plist = &A;
A.sign = ’+’; B.sign = ’-’; E.sign = ’-’;
A.next = &B; B.next = &E; E.next = &C;
A.childlist = &B; B.childlist = &C; E.childlist = NULL;
A.sibling = &F; B.sibling = &E; E.sibling = NULL;
C.sign = ’+’; D.sign = ’+’; F.sign = ’+’;
C.next = &D; D.next = &F; F.next = &G;
C.childlist = NULL; D.childlist = NULL; F.childlist = &G;
C.sibling = &D; D.sibling = NULL; F.sibling = NULL;
G.sign = ’-’; H.sign = ’+’; I.sign = ’-’;
G.next = &H; H.next = &I; I.next = NULL;
G.childlist = &H; H.childlist = &I; I.childlist = NULL;
G.sibling = NULL; H.sibling = NULL; I.sibling = NULL;
2.3描绘参数

Potrace的描绘操作由少量参数控制。参数结构在potracelib.h中定义为:

struct potrace_param_s {
int turdsize;
int turnpolicy;
double alphamax;
int opticurve;
double opttolerance;
potrace_progress_t progress;
};
typedef struct potrace_param_s potrace_param_t;

对于大多数实际应用,默认参数都会产生很好的结果。函数potrace_param_default()(参见第3.3节)返回一组默认参数。在更改任何参数之前,应用程序必须始终从这些默认参数。这将会提高将来添加其它参数时的向后兼容性。

2.3.1Turdsize参数

turdsize参数可用于对需要描绘的位图去斑,方法是删除封闭区域低于给定阈值的所有曲线。图7显示了将turdsize=3应用于位图的结果。Turdsize参数的当前默认值参数是2;它的有效范围是从0到无穷大。
图7. turdsize=3去斑。
图7. turdsize=3去斑。

2.3.2Turnpolicy参数

turnpolicy参数决定如何在将位图分解为路径的过程中解决歧义。歧义性出现在图8所示的最后一种情况中。TurnPolicy参数的可能选择是:
•POTRACE_TURNPOLICY_BLACK:倾向于连接黑色(前景)组件。
•POTRACE_TURNPOLICY_WHITE:倾向于连接白色(背景)组件。
•POTRACE_TURNPOLICY_LEFT:始终左转。
•POTRACE_TURNPOLICY_RIGHT:始终右转。
•POTRACE_TURNPOLICY_MINORITY:倾向于连接在当前位置的本地邻居中最不经常出现的颜色(黑色或白色)。
•POTRACE_TURNPOLICY_MAJORITY:倾向于连接在当前位置的本地邻居中最经常出现的颜色(黑色或白色)。
•POTRACE_TURNPOLICY_RANDOM:伪随机选择。
当前的默认策略是POTRACE_TURNPOLICY_MINORITY,它倾向于保持可视线路是连通的。

图8. 路径分解。

2.3.3Alphamax参数

alphamax参数是检测转角的阈值。它控制描绘曲线的平滑度,如图9所示。当前默认值为1.0。此参数的有效范围是从0.0(多边形)到1.3334(无角)。

图9. alphamax参数。

2.3.4Opticurve和opttolerance参数

opticurve参数是一个布尔标志,用于控制Potrace是否通过减少贝塞尔曲线段的数量来“简化”最终曲线。opticurve=1打开优化,opticurve=0关闭优化。当前默认设置为“打开”。

opttolerance参数定义此简化中允许的错误量。当前默认值为0.2。较大的值往往会减少线段的数量,但会降低精度。有用的范围是从0到无穷大,但是在实践中人们几乎不会选择大于1的值。对于大多数应用,默认值是空间和准确性之间的一个很好的折衷。

2.3.5Opticurve和opttolerance参数

由于跟踪一个大的位图可能很耗时,因此Potrace可以选择向调用应用程序报告进度。这通常用在交互式应用程序中的进度条实现。进度报告由进度参数控制,该参数是potrace_progress_t类型的结构,定义如下:

struct potrace_progress_s {
void (*callback)(double progress, void *privdata);
void *data;
double min, max;
double epsilon;
};
typedef struct potrace_progress_s potrace_progress_t;

如果callback不为空,则启用进度报告。在这种情况下,callback是被进度报告调用的函数的地址,data是指向该函数私有数据的指针。进度报告采用callback(d, data)的形式,其中d是表示从最小到最大范围内相对进度量的数字。

参数epsilon是一个提示,它把应用程序认为“太小而无法报告”的进度量报告给Potrace。如果从前一个报告结束算起,到现在的进度增量小于epsilon,那么Potrace在任何时候都可以随意减少进度报告。特殊情况下,如果epsilon=0,则发送最大进度报告数。因为可能会有大量的报告出现,所以在任何情况下应用程序都应该高效地处理进度报告。

默认值为callback=null、data=null、min=0.0、max=1.0和epsilon=0。

2.4Potrace状态

Potrace状态保存描绘操作的结果。定义如下:

struct potrace_state_s {
int status;
potrace_path_t *plist; /* vector data */
struct potrace_privstate_s *priv; /* private state */
};
typedef struct potrace_state_s potrace_state_t;

字段如下:
•status字段为OTRACE_STATUS_OK则表示描绘操作成功,或者POTRACE_STATUS_INCOMPLETE,表示描绘操作失败。
•如果成功,plist指向第2.2.5节中所述的双向描绘矢量图的描述。如果失败,plist指向属性未定义的数据结构,但是仍然可以使用potrace_state_free()释放Potrace状态。
•priv字段由Potrace在内部使用,应用程序无法访问。

3.API函数

potracelib中没有全局或静态状态;所有API函数都是可重入的和线程安全的。

3.1potrace trace
potrace_state_t *potrace_trace(const potrace_param_t *param,
const potrace_bitmap_t *bm);

输入:
•bm:一张位图(见第2.1节)。
•param:一组描绘参数(见第2.3节)。
输出:
•一个Potrace状态(见第2.4节)。

此函数尝试使用给定的描绘参数来描绘给定的位图。

如果成功,它将返回一个有效的Potrace状态,设置status字段为POTRACE_STATUS_OK。如果失败,它将errno设置为错误数,然后返回NULL,或者返回不完整的Potrace状态,根据定义,该状态字段设置为POTRACE_STATUS_INCOMPLETE。potrace_trace()返回的任何Potrace状态(无论是有效还是无效)都可以使用下面的potrace_state_free()函数释放。

3.2potrace state free

输入:
•st:先前由potrace_trace()返回的potrace状态。
此函数释放与Potrace状态关联的内存和其它资源(如果有的话)。

3.3potrace state free
void potrace_state_free(potrace_state_t *st);

输出:
•一组描绘参数(见第2.3节)。
此函数返回一组新的描绘参数,已初始化为默认值。应用程序必须始终使用此函数创建potrace_param_t类型的对象,并且在修改任何参数之前,它们必须始终从默认参数开始。这将有助于在将来添加其它参数时提高向后兼容性。此函数返回的参数集稍后可以由potrace_param_free()释放。

3.4potrace param free()
void potrace_param_free(potrace_param_t *p);

输入:
•描绘先前由potrace_param_default()返回的参数。
此函数释放potrace_param_default()返回的一组描绘参数占用的内存。只释放由potrace初始化的字段,而不释放由应用程序本身设置的任何字段(如progress.data)。

3.5potrace version()
const char *potrace_version();

此函数返回标识此版本的potracelib的静态可读文本字符串。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值