
在开发过程中,有时候UIKit的标准控件并不能满足我们的需求,例如你需要一个控件能支持用户方便的选择0-360°之间的一个角度值,此时就需要根据自己的需求自定义控件了。
对于选择角度值的控件可以这样实现:创建一个圆形的滑块,用户通过拖动手柄 *** 作就能选择角度值。实际上这样的控件在别的一些平台中你可能看到过,但是在UIKit中并没有。
本文就实现一个选择角度值的控件来介绍控件的自定义。下面先来看看到底要做成什么样子:
1 子类化UIControl
UIControl 是UIView的子类,它又是所有UIKit控件的父类(例如UIButton、UISlider和UISwitch等)。
UIControl的主要作用是创建相应的逻辑将action分发到对应的target,另外90%的情况下,它会根据自身的状态(例如Highlighted, Selected和Disabled等)来绘制用户界面。
通过UIControl,我们主要管理3个重要的任务:
绘制用户界面
跟踪用户的 *** 作
Target-Action模式
在本文的圆形滑块中,我们要做如下一些事情:
定制一个用户界面(圆形滑块本身),通过该界面用户可以通过手柄进行界面交互。用户的交互 *** 作会被转换为控件target对应的action(控件将滑块按钮的frame origin转换为0-360之间的一个值,并用于target/action上)。
建议在学习本文的时候从文章尾部的连接中下载完整的示例工程。
下面我将从上面列出的3个重要任务一一进行分解介绍。
这些步骤都是模块化的,所以如果你对界面的绘制不感兴趣,可以跳 绘制用户界面 ,直接学习后面的步骤。
打开工程文件中的 TBCircluarSliderm 文件。然后开始学习下面的内容。
11 绘制用户界面
我比较喜欢使用Core Graphics,唯一用到UIKit的就是通过textfield来显示滑块的值。
提醒 :此处需要用到一些 Core Graphics 知识,如果你不懂也没多大关系,我会尽量把代码做详细的讲解。
我们先来看看控件的不同组成部分,这样更有利于后面的学习。
首先,是用一个 黑色的圆环 当做滑块的背景。
可 *** 作区域(active area) 是一个从蓝色到紫色的梯度渐变效果。
用户通过拖拽下面的这个手柄按钮来选择值:
最后,用于显示选中值的 TextField 。在下一版中,我计划让用户可以通过键盘输入角度值。
控件界面的绘制主要使用drawRect函数,首选我们需要获取到当前使用的图形上下文,如下代码所示:
1
CGContextRef ctx = UIGraphicsGetCurrentContext();
111 绘制背景
背景是360°的,所以只要用CGContextAddArc给图形上下文添加正确的path,并设置正确的stroke即可。
下面的代码可以就可以完成背景的绘制:
//Add the arc path
CGContextAddArc(ctx, selfframesizewidth/2, selfframesizeheight/2, radius, 0, M_PI 2, 0);
//Set the stroke colour
[[UIColor blackColor]setStroke];
//set Line width and cap
CGContextSetLineWidth(ctx, TB_BACKGROUND_WIDTH);
CGContextSetLineCap(ctx, kCGLineCapButt);
//draw it!
CGContextDrawPath(ctx, kCGPathStroke);
CGContextArc 函数的参数包括图形上下文,弧度的中心坐标点,以及半径(是一个私有变量),接着是弧度开始和结束时的角度(在TBCircularSliderm文件的头部可以看到一些关于数学计算的方法),最后一个参数标示绘制的方向,0表示逆时针方向。
接下来的3行的代码是用来设置一些信息的,例如颜色和线条宽度等。最后使用 CGContextDrawPath 方法完成背景的绘制。
112 绘制用户的可 *** 作区域
这部分需要利用一点小技巧才行。此处我们绘制一个线性渐变的掩码,下面看看原理:
此处掩码的工作原理是可以看到原始渐变矩形框的一个孔。
在这里绘制的弧度有一个阴影,这是创建掩码图时使用了一点模糊的效果。
下面是创建掩码图的相关代码:
UIGraphicsBeginImageContext(CGSizeMake(320,320));
CGContextRef imageCtx = UIGraphicsGetCurrentContext();
CGContextAddArc(imageCtx, selfframesizewidth/2 , selfframesizeheight/2, radius, 0, ToRad(selfangle), 0);
[[UIColor redColor]set];
//Use shadow to create the Blur effect
CGContextSetShadowWithColor(imageCtx, CGSizeMake(0, 0), selfangle/20, [UIColor blackColor]CGColor);
//define the path
CGContextSetLineWidth(imageCtx, TB_LINE_WIDTH);
CGContextDrawPath(imageCtx, kCGPathStroke);
//save the context content into the image mask
CGImageRef mask = CGBitmapContextCreateImage(UIGraphicsGetCurrentContext());
UIGraphicsEndImageContext();
在上面的代码中首先创建了一个图形上下文,然后设置了一下阴影。通过 CGContextSetShadowWithColor 方法,我们可以设置如下内容:
上下文
偏移量(此处不需要)
模糊值(该值是通过参数控制的:使用当前的角度除以20,当用户与此控件交互时,以此获得一个简单的动画模糊值)
颜色
接着是根据当前的角度绘制一个相应的弧度。
例如,如果当前的角度变量是360°,那么就绘制一个圆弧,如果是90°,就绘制一个弧度为90°的一个弧。最后,利用 CGBitmapContextCreateImage 方法获取一张(刚刚绘制的弧)。这个就是我们所需要的掩码图了。
裁剪上下文:
现在我们已经有一个渐变的掩码图了。接着利用函数 CGContextClipToMask 对上下文进行裁剪——给该函数传入上面刚刚创建好的掩码图。代码如下所示:
CGContextClipToMask(ctx, selfbounds, mask);
最后我们来绘制渐变效果,代码如下所示:
//Define the colour steps
CGFloat components[8] = {
00, 00, 10, 10, // Start color - Blue
10, 00, 10, 10 }; // End color - Violet
CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, components, NULL, 2);
//Define the gradient direction
CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
//Choose a colour space
CGColorSpaceRelease(baseSpace), baseSpace = NULL;
//Create and Draw the gradient
CGContextDrawLinearGradient(ctx, gradient, startPoint, endPoint, 0);
CGGradientRelease(gradient), gradient = NULL;
绘制渐变效果需要很多处理,不过我们可以将其分为4部分:
定义颜色的变化范围
定义渐变的方向
选择颜色空间
创建并绘制渐变
最终的显示效果(看到渐变矩形框的一部分)要归功于之前创建的掩码图。
另外,为了在背景边框模拟光线反射,我添加了一些灯光效果。
113 绘制手柄
下面我们根据当前的角度值,在的正确位置绘制出手柄。
实际上,在绘制过程中,这一步非常简单,复杂一点的就是计算一下手柄所在的位置。
这里我们需要使用三角函数将一个 标量值(scalar number) 转换为 CGPoint 。不要担心有多复杂,只需要使用Sin和Cos函数就可以完成。代码如下所示:
-(CGPoint)pointFromAngle:(int)angleInt{
//Define the Circle center
CGPoint centerPoint = CGPointMake(selfframesizewidth/2 - TB_LINE_WIDTH/2, selfframesizeheight/2 - TB_LINE_WIDTH/2);
//Define The point position on the circumference
CGPoint result;
resulty = round(centerPointy + radius sin(ToRad(-angleInt))) ;
resultx = round(centerPointx + radius cos(ToRad(-angleInt)));
return result;
}
上面的代码中,指定一个角度值,然后计算出在圆周上面的位置,当然,这里需要圆周的中心点和半径。
使用sin函数在使用sin函数时,需要一个Y坐标值,而cos函数则需要X坐标值。
需要注意的是此处每个函数返回的值都认为半径为1,所以需要将所得结果乘以我们指定的半径大小,并相对于圆周的中心做计算。
希望下面的公式对你的理解有所帮助:
1
2
pointy = centery + (radius sin(angle));
pointx = centerx + (radius cos(angle));
通过上面的计算,现在我们已经知道手柄的具体位置了,所以,接下来就直接将手柄绘制到指定位置即可,如下代码所示:
-(void) drawTheHandle:(CGContextRef)ctx{
CGContextSaveGState(ctx);
//I Love shadows
CGContextSetShadowWithColor(ctx, CGSizeMake(0, 0), 3, [UIColor blackColor]CGColor);
//Get the handle position!
CGPoint handleCenter = [self pointFromAngle: selfangle];
//Draw It!
[[UIColor colorWithWhite:10 alpha:07]set];
CGContextFillEllipseInRect(ctx, CGRectMake(handleCenterx, handleCentery, TB_LINE_WIDTH, TB_LINE_WIDTH));
CGContextRestoreGState(ctx);
}
具体 *** 作步骤如下:
保存当前的上下文(当在一个单独的函数中进行绘制任务时,将上下文的状态进行保存是编程的一个好习惯)。
给手柄设置一些阴影效果
定义手柄的颜色,然后利用 CGContextFillEllipseInRect 将其绘制出来。
我们在drawRect函数的最后调用上面这个方法:
1
[self drawTheHandle:ctx];
至此,我们就完成了绘制部分的任务。
12 跟踪用户的 *** 作
在UIControl的子类中,我们可以 override 3个特殊的方法来提供一个自定义的跟踪行为
121 开始跟踪
当在控件的bound内发生了一个触摸事件,首先会调用控件的 beginTrackingWithTouch 方法。
我们就看看如何 override 这个方法吧:
-(BOOL)beginTrackingWithTouch:(UITouch )touch withEvent:(UIEvent )event{
[super beginTrackingWithTouch:touch withEvent:event];
//We need to track continuously
return YES;
}
该函数返回的BOOl值决定着:当触摸事件是dragged时,是否需要响应。在我们这里的自定义控件中,是需要跟踪用户的dragging,所以返回YES。
上面这个函数有两个参数:touch对象和事件。
122 持续跟踪
在上一个方法中我们指定了这里的自定义控件需要跟踪一个持续的事件,所以当用户进行drag时,会调用一个特殊的方法: continueTrackingWithTouch :
-(BOOL)continueTrackingWithTouch:(UITouch )touch withEvent:(UIEvent )event
该方法返回的BOOL值标示是否继续跟踪touch事件。
通过该方法我们可以根据touch位置对用户的 *** 作进行过滤。例如,我们可以:仅当touch位置与手柄位置相交的时候才激活控件(activate control)。不过在这里我们的控制逻辑并不是这样的,我们希望用户点击任何位置都能对手柄做出相应的位置处理。
本文的该方法负责更新手柄的位置(在后面的一节中会看到我们把该位置信息传递给对应的target上)。
对上面这个方法的override代码如下所示:
-(BOOL)continueTrackingWithTouch:(UITouch )touch withEvent:(UIEvent )event{
[super continueTrackingWithTouch:touch withEvent:event];
//Get touch location
CGPoint lastPoint = [touch locationInView:self];
//Use the location to design the Handle
[self movehandle:lastPoint];
//We'll see this function in the next section:
[self sendActionsForControlEvents:UIControlEventValueChanged];
return YES;
}
上面的代码中,首先利用 locationInView 获取到touch的位置,然后将该位置传递给 moveHandle 方法,该方法会将传入的值转换为一个有效的手柄位置(a valid handle position)。
此处“a valid position”的意思是什么呢?
此控件的手柄只能在背景圆弧定义的边界范围内做移动,但是我们不希望强制要求用户必须在很小的圆弧内才可以移动手柄,如果非要这样的话,用户体验会非常的糟糕。
moveHandle 的任务就是负责把任意的位置值转变为手柄可移动的值,另外,另外,在该函数中,还对指定的滑块角度值做了转换,代码如下所示:
-(void)movehandle:(CGPoint)lastPoint{
//Get the center
CGPoint centerPoint = CGPointMake(selfframesizewidth/2,
selfframesizeheight/2);
//Calculate the direction from the center point to an arbitrary position
float currentAngle = AngleFromNorth(centerPoint,
lastPoint,
NO);
int angleInt = floor(currentAngle);
//Store the new angle
selfangle = 360 - angleInt;
//Update the textfield
_textFieldtext = [NSString stringWithFormat:@"%d",
selfangle];
//Redraw
[self setNeedsDisplay];
}
上面代码中,实际上主要任务都是在 AngleFromNorth 方法中处理的:根据两个point,就会返回一个连接这两点对应的一个角度关系, AngleFromNorth 方法的实现如下所示:
static inline float AngleFromNorth(CGPoint p1, CGPoint p2, BOOL flipped) {
CGPoint v = CGPointMake(p2x-p1x,p2y-p1y);
float vmag = sqrt(SQR(vx) + SQR(vy)), result = 0;
vx /= vmag;
vy /= vmag;
double radians = atan2(vy,vx);
result = ToDeg(radians);
return (result >=0 result : result + 3600);
}
提醒: angleFromNorth 方法并不是我的原创,我是直接从苹果提供的OSX示例clockControl中拿过来用的。
在上面的代码中,获得了角度值以后,将其存储到 angle 中,然后更新一下textfield的值。
接着调用的 setNeedDisplay 是为了确保 drawRect 被调用,以尽快在界面上做出相应的更新。
123 结束跟踪
当跟踪结束的时候,会调用下面这个方法:
-(void)endTrackingWithTouch:(UITouch )touch withEvent:(UIEvent )event{
[super endTrackingWithTouch:touch withEvent:event];
}
在本文中,我们并不需要override该方法。如果当用户完成控件的界面 *** 作时,你希望做一些处理,那么该方法会非常有用。
13 Target-Action模式
至此,圆形滑块控件可以工作了,你可以drag手柄,并能看到textfield中值的改变。
发送action——控件事件
如果希望自己定制的控件与UIControl行为保持一致,那么当控件的值发生变化时,需要进行通知处理:使用 sendActionsForControlEvents 方法,并制定特定的事件类型,值改变对应的事件一般是 UIControlEventValueChanged 。
苹果已经预定义了许多事件类型(Xcode中,在UIControlEventValueChanged上 cmd + 鼠标单击 )。如果你的控件是继承自UITextField,那么你可能会对 UIControlEventEdigitingDidBegin 感兴趣,如果你要做一个touch Up action,那么可以使用UIControlTouchUpInside。
如果你注意的话,在本文前部分的continueTrackingWithTouch方法里面,我们调用了 sendActionsForControlEvents 方法:
[self sendActionsForControlEvents:UIControlEventValueChanged];
这样处理之后,当控件值发生变化时,每一个对象(观察者——注册该事件)都会收到响应的通知。
'SavePicture方法保存ico图标时会失真,他保存真彩色时候会自动把图标转换成256色,这也是这个方法保存ico的不足,除非自己懂ico文件结构,把ico图标数据自己写到文件中,否则该函数会自动将真彩色
转换
256色保存,放在picturebox中的已经不是ico图标了,那是bmp,即使把bmp背景去掉还是要显示出来,ico里面有2张位图,一张是真图,另一张是掩码图(掩码图就是在显示的时候去除真图中不该显示的地方,比如说把ico图标放在桌面显示,系统会将ico的真图和掩码图拿出来,通过掩码图进行一种图像的叠加计算,让真图不该显示的地方去掉,让这个去掉的地方显示桌面的背景图)
Private
Type
PicBmp
Size
As
Long
tType
As
Long
hBmp
As
Long
hPal
As
Long
Reserved
As
Long
End
Type
Private
Type
GUID
Data1
As
Long
Data2
As
Integer
Data3
As
Integer
Data4(7)
As
Byte
End
Type
Private
Declare
Function
ExtractIcon&
Lib
"shell32dll"
Alias
"ExtractIconA"
(ByVal
hInst
As
Long,
ByVal
lpszExeFileName
As
String,
ByVal
nIconIndex
As
Long)
Private
Declare
Function
OleCreatePictureIndirect
Lib
"olepro32dll"
(PicDesc
As
PicBmp,
RefIID
As
GUID,
ByVal
fPictureOwnsHandle
As
Long,
IPic
As
Picture)
As
Long
Private
Declare
Function
ExtractIconEx
Lib
"shell32dll"
Alias
"ExtractIconExA"
(ByVal
lpszFile
As
String,
ByVal
nIconIndex
As
Long,
phiconLarge
As
Long,
phiconSmall
As
Long,
ByVal
nIcons
As
Long)
As
Long
Private
Declare
Function
DestroyIcon
Lib
"user32"
(ByVal
hIcon
As
Long)
As
Long
Public
Function
GetIconFromFile(FileName
As
String)
As
Picture
Dim
hlargeicon
As
Long,
hsmallicon
As
Long,
selhandle
As
Long
Dim
pic
As
PicBmp,
IPic
As
IPicture,
IID_IDispatch
As
GUID
selhandle
=
ExtractIcon(0,
FileName,
0)
If
selhandle
>
0
Then
With
IID_IDispatch
Data1
=
&H20400
Data4(0)
=
&HC0
Data4(7)
=
&H46
End
With
With
pic
Size
=
Len(pic)
tType
=
vbPicTypeIcon
hBmp
=
selhandle
End
With
Call
OleCreatePictureIndirect(pic,
IID_IDispatch,
0,
IPic)
Picture1Picture
=
IPic
Set
GetIconFromFile
=
IPic
DestroyIcon
hsmallicon
DestroyIcon
hlargeicon
End
If
End
Function
Private
Sub
Form_Load()
SavePicture
GetIconFromFile("exe文件路径"),
"保存的位置ico"
End
Sub
设置无线路由器怎么填写Ip地址,子网掩码默认网关
一般路由器都是不用设置 IP 子网和默认网关的,不知道你设置了用来干嘛,如果真要设置的话,你的路由器网段如果是19216811的话
IP 1921681103 IP不一定是这个,最后一个数字你可以自己设
子网 2552552550
默认网关的话就是19216811了
若你路由是0段的,
那一次是1921680103
2552552550
19216801
无线路由器子网掩码怎么设置 苹果6设置无线是ip地址的子网掩码是多少
1:单机桌面右上角的无线图标,无线网卡自动搜索环境中的无线网络,
2:点击“打开网络偏好设置”,进入“网络偏好设置”界面,
3:选择需要设置IP地址的网卡(本例中以无线网卡为例)。选择“AirPort”,接着点击“高级”,进入“AirPort”网络参数设置页面。选择“TCP/IP”,进入IP地址设置界面,
4:您可以根据您的实际网络使用情况,选择手动配置IP或者DHCP,并设置相关参数。
A 手动配置IP:打开“配置IPv4”下拉框,选择“手动”,为无线网卡手动指定IP地址等参数。例如:
IP地址 :192168190
子网掩码:2552552550
路由器:可根据您的网络选择填写,本例中留空。
设置完毕之后,点击“好”,返回“网络偏好设置”界面,点击“应用”,设置生效。
B DHCP, 电脑自动获取IP地址等网络参数。进入“AirPort”网络参数设置页面,选择“TCP/IP”,进入IP地址设置界面,
选择“使用DHCP”,设置完毕。点击“好”,返回“网络偏好设置”页面,点击“应用”使所有设置生效。
WiFi设置的时候子网掩码是什么
子网掩码 是IP 参照物
分网段用的!
比如 19216801 和19216802
1子网掩码为 2552552550
那么1921680X 在同一个网段,能互相访问
2希望掩码为 25525500
那么 192168XX在同一个网段,能互相访问]
路由器静态IP地址、子网掩码怎么设置
首先你地知道你wan口的网段,然后填上ip和主网在意网段。子网掩码2552552550网关填意路由上一级路由的ip地址,dns和上一级一样。这个低你自己查
在固定IP的局域网内使用无线路由,子网掩码应该怎么填写?
你发的这个图是单位的总路由器在拨号?
如果是,在lan口设置里,修改自己路由器的ip为192168101wan口设置里,选择静态ip,依次填写分配给你这台路由器的ip、掩码等信息。
保存重启之后,再把单位的网线插入wan口。
以后要用192168101进自己的路由器。
无线路由器设置,家里IP是192168966,怎么设置啊,子网掩码什么的,急! 20分
你的IP192168966,网关是19216891子网掩码是2552552550,如果不是的话可以在:开始--运行--输入CMD--再输入IPCONFIG -ALL 回车即可
看到了,你的网关是1921689254,你就照这个输入进去
无线路由器的IP ,子网掩码,默认网关是多少呢
无线路由器的IP 1921680101
子网掩码,2552552550
默认网关是多少呢 19216801
无线的怎么设置固定的ip地址?固定的ip地址是什么?子网掩码是多少?默认网关是什么
其实你点自动ip地址就可以了,如果不行,你就试下我这个。箭头那个可以选择2-254之间的任意数字。
没有IP地址和子网掩码怎么设置无线路由器
你是固定ip上网吗;如果是固定ip上网;运营商会把ip地址;子网掩码;dns服务器密码告诉你的
你忘记了可以咨询地点运营商
如果不是固定ip地址上网;选择网络连接类型:这里我们选择PPP OE拨号用户;不需要输入
IP地址和子网掩码路由器会自动获取的
子网掩码不能单独存在,它必须结合IP地址一起使用。子网掩码只有一个作用,就是将某个IP地址划分成网络地址和主机地址两部分。
子网掩码的设定必须遵循一定的规则。与IP地址相同,子网掩码的长度也是32位,左边是网络位,用二进制数字“1”表示;右边是主机位,用二进制数字“0”表示。附图所示的就是IP地址为“19216811”和子网掩码为“2552552550”的二进制对照。其中,“1”有24个,代表与此相对应的IP地址左边24位是网络号;“0”有8个,代表与此相对应的IP地址右边8位是主机号。这样,子网掩码就确定了一个IP地址的32位二进制数字中哪些是网络号、哪些是主机号。这对于采用TCP/IP协议的网络来说非常重要,只有通过子网掩码,才能表明一台主机所在的子网与其他子网的关系,使网络正常工作。
一维条码和二维码的主要区别,在于二维码能够包含更多的信息,这种信息可以是文字、、音频、视频、链接等。
如果单从防伪这块讲的话,二维码防伪技术更为先进,防伪效果也会更好。
希望对楼主有帮助。
'SavePicture方法保存ico图标时会失真,他保存真彩色时候会自动把图标转换成256色,这也是这个方法保存ico的不足,除非自己懂ico文件结构,把ico图标数据自己写到文件中,否则该函数会自动将真彩色 转换 256色保存,放在picturebox中的已经不是ico图标了,那是bmp,即使把bmp背景去掉还是要显示出来,ico里面有2张位图,一张是真图,另一张是掩码图(掩码图就是在显示的时候去除真图中不该显示的地方,比如说把ico图标放在桌面显示,系统会将ico的真图和掩码图拿出来,通过掩码图进行一种图像的叠加计算,让真图不该显示的地方去掉,让这个去掉的地方显示桌面的背景图)
Private Type PicBmp
Size As Long
tType As Long
hBmp As Long
hPal As Long
Reserved As Long
End Type
Private Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(7) As Byte
End Type
Private Declare Function ExtractIcon& Lib "shell32dll" Alias "ExtractIconA" (ByVal hInst As Long, ByVal lpszExeFileName As String, ByVal nIconIndex As Long)
Private Declare Function OleCreatePictureIndirect Lib "olepro32dll" (PicDesc As PicBmp, RefIID As GUID, ByVal fPictureOwnsHandle As Long, IPic As Picture) As Long
Private Declare Function ExtractIconEx Lib "shell32dll" Alias "ExtractIconExA" (ByVal lpszFile As String, ByVal nIconIndex As Long, phiconLarge As Long, phiconSmall As Long, ByVal nIcons As Long) As Long
Private Declare Function DestroyIcon Lib "user32" (ByVal hIcon As Long) As Long
Public Function GetIconFromFile(FileName As String) As Picture
Dim hlargeicon As Long, hsmallicon As Long, selhandle As Long
Dim pic As PicBmp, IPic As IPicture, IID_IDispatch As GUID
selhandle = ExtractIcon(0, FileName, 0)
If selhandle > 0 Then
With IID_IDispatch
Data1 = &H20400
Data4(0) = &HC0
Data4(7) = &H46
End With
With pic
Size = Len(pic)
tType = vbPicTypeIcon
hBmp = selhandle
End With
Call OleCreatePictureIndirect(pic, IID_IDispatch, 0, IPic)
Picture1Picture = IPic
Set GetIconFromFile = IPic
DestroyIcon hsmallicon
DestroyIcon hlargeicon
End If
End Function
Private Sub Form_Load()
SavePicture GetIconFromFile("exe文件路径"), "保存的位置ico"
End Sub
没必要那么麻烦只要使用GDI+库里面的Bitmap对象和Graphics对象就可以了。WindowsXP以上的OS都提供GDI+图形接口了,他的功能比GDI接口更强大,使用更方便。建议你可以查查GDI+的用法。这里给你个最简单的C#的例子:
SystemDrawingBitmap bmp = new Bitmap("1png");//创建Bitmap对象
SystemDrawingColor c = bmpGetPixel(0, 0);//获得图像上(0,0)点的像素值
int a = cA;//该像素的Alpha通道值
int r = cR;//该像素的红色通道值
int g = cG;//该像素的绿色通道值
int b = cB;//该像素的蓝色通道
那建议你上网查一查PNG格式的标准,就知道PNG文件里的数据排列了。但PNG是压缩过的,所以你还得有解压算法才行。
png的存储格式:
关键数据块中有4个标准数据块:
文件头数据块IHDR(header chunk):包含有图像基本信息,作为第一个数据块出现并只出现一次。
调色板数据块PLTE(palette chunk):必须放在图像数据块之前。
图像数据块IDAT(image data chunk):存储实际图像数据。PNG数据允许包含多个连续的图像数据块。
图像结束数据IEND(image trailer chunk):放在文件尾部,表示PNG数据流结束。
在第二个数据块中包含了调色板数据块。可是,当我们去解析png24时,却未找到调色板、并且我们发现png24的存储模式是点阵颜色值加一位的阿尔法通道值构成的,这种存储模式根本不需要调色板的存在。基于这种存储模式,png24的位深最低是32位真彩,在我们看到的图像过渡中会很圆润,因为每个点都可以是不同的色彩以及不同的透明值。而这种模式也是我们最常使用、大家所理解中的png模式。至于"png"后面的“24”可见也和位深并无关系,至于为什么叫24,我也没有找到具体的答案。
png24源数据中无调色盘的存在,而在标准数据块的第二块中,却显示了调色板数据块。即然存在,肯定是有意义的,可见png有另外一种存储模式--带色盘的png8模式。png8有点类似于GIF,包含了一个调色板,并在调色板上有一个透明颜色值,这种模式在计算机的存储中,每个点阵存储的是色盘索引、并且无阿尔法半透明位。所以,png8在颜色位深上,可以低于32位;也可以使用更换色盘的技术来处理一些独特的效果;但是由于每个点阵没有阿尔法定义,边缘会像GIF一样存在锯齿现像。
好像讲的有点乱,总结一下区别吧:
png8和png24的根本区别,不是颜色位的区别,而是存储方式不同;
png8 色盘索引、调色板中一位透明值、不支持阿尔法通道的半透明,存储格式中每个像素无透明度的数据块定义;
png24 无调色板、支持阿尔法通道的半透明、每个点阵都有透明度的定义,最低32位真彩色;
特性
支持256色调色板技术以产生小体积文件
最高支持48位真彩色图像以及16位灰度图像。
支持阿尔法通道的半透明特性。
支持图像亮度的gamma校正信息。
支持存储附加文本信息,以保留图像名称、作者、版权、创作时间、注释等信息。
使用无损压缩
渐近显示和流式读写,适合在网络传输中快速显示预览效果后再展示全貌。
使用CRC循环冗余编码防止文件出错。
最新的PNG标准允许在一个文件内存储多幅图像。
看。有使用无损压缩和多幅图像。挺复杂的哦!
>
以上就是关于如何自定义iOS中的控件全部的内容,包括:如何自定义iOS中的控件、VB 提取exe 中的图标(ICO)、如何设置无线子网掩码等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)