外文翻译译文部分SWT图像.docx
《外文翻译译文部分SWT图像.docx》由会员分享,可在线阅读,更多相关《外文翻译译文部分SWT图像.docx(29页珍藏版)》请在冰豆网上搜索。
外文翻译译文部分SWT图像
浅谈SWT图像
概要
SWT的图像类能用来在GUI里显示图象。
图像的最普通的来源是从标准文件形式(例如GIF,JPEG,PNG或者BMP)中下载。
一些控制,包括按钮和TreeItems,能直接通过setImage方法来展示一幅图像,但是任何控制绘图的事件都允许图像从图表库中提取。
SWT的ImageData类描述制作一幅SWT图像的原始数据并且决定了屏幕上每个坐标的象素颜色。
这篇文章展示了ImageData类和图像的正确的用法,显示如何从文件中载入图像,和怎样表现透明度,调和α,动画,调节比例和光标这样的图表效应。
ByJoeWinchester,IBM
2003年9月10日
这篇文章的第一部分介绍了颜色并且展示了一幅图像是怎样记录每个象素色值的。
∙简介
∙图像生存周期
∙ImageData
∙颜色
∙PaletteData
o索引调色板
o直接调色板
下一部分描述图像为的透明度,调和,动画和如何调节图像比例。
∙透明度
∙操作ImageData
∙保存图像
∙调和
o单个alpha值
o每个像素不同的α值
∙图像效应
∙GIF动画
∙比例
最后,文章还告诉我们如何应用源映像和面具来在图像中创建光标。
∙光标
∙平台光标
∙惯用光标
简介
建立一幅SWT图像的最简单的方法是从公认的图表文件形式中下载它。
这包括GIF,BMP(Windows形式bitmap),JPG和PNG。
在最近发布的Eclipse中TIFF形式得到更多的支持。
图像可以从应用建有图像的文件系统中已知的位置载入
(Displaydisplay,StringfileLocation):
Imageimage=newImage(display,
"C:
/eclipse/eclipse/plugins/org.eclipse.platform_2.0.2/eclipse_lg.gif");
不需要费力编码图像的位置,我们通常从规定的相关类中有关的文件夹位置载入图像。
这是通过建立输出流时指定文件路径来完成的Class.getResourceAsStream(Stringname),然后使用结果作为建造者建图像的理由(Displaydisplay,InputStreaminputStream)。
下面的Eclipse包explorer展示了com.foo.ShellWithButtonShowingEclipseLogo和eclipse_lg.gif在同一个文件夹里。
为遵循代码将会从相关类位置下载图像。
Imageimage=newImage(display,
ShellWithButtonShowingEclipseLogo.class.getResourceAsStream(
"eclipse_lg.gif"));
一旦图像被创建,它就被用作了控制的一部分,例如按钮和标签,它们能使图表成为其setImage(Imageimage)方法的一部分。
Buttonbutton=newButton(shell,SWT.PUSH);
button.setImage(image);
我们可以用已建的GC(Drawabledrawable)图像库来绘图:
GCgc=newGC(image);
gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE));
gc.drawText("I'vebeendrawnon",0,0,true);
gc.dispose();
用GC来绘制图像会永久改变图像。
文章中还有更多的关于如何使用GC的信息。
详见图形库-快览拖拽.
图像生存周期
载入图像时,第一步是创造独立的ImageData类,用org.eclipse.swt.graphics.ImageData来描述。
接下来,数据通过创造一个实际图像实例为一个具体的设备作准备。
当从一个文件直接载入一幅图像时,可以单独建立一个ImageData对象,然后使用Image(Devicedevice,ImageDataimageData)建图像。
尽管不是用来被创建图像的相同对象,但是我们可以使用getImageData()方法来取回数据。
这是因为当你准备在屏幕上绘制一个图像时比如颜色深度这类属性是不同于最初的图象数据的。
图像的实例是为一个具体的设备作准备的一种基础的资源,当分配资源不再免费时,这些实例就会被处理掉。
在SWT中,当一个对象被垃圾站回收时资源是没有最终化的。
更多的信息详见SWT:
标准窗口工具:
操作系统管理系统.
ImageData
ImageData可以被认为是一幅图像的模型,而图像是准备输出一个具体的设备时的映像。
ImageData包括宽度,高度和每个坐标的象素值。
图像的初始数据是字节[],图像的深度指坐标的比特值。
1位图像深度可以为每个象素(0和1)储存两个可能值,4位深度能储存2^4=16,8位深度能储存2^8=256值,24位深度能为每个像素储存2^24=1600万不同的值。
图像的深度越大像素所需要的字节数越多,而有些文件形式,比如GIF格式,为了通过链接因特网下载图片最初设计只支持最大为8位的图像深度。
每个象素值是怎样转化为一种实际颜色的,这取决于类的调色板org.eclipse.swt.graphics.PaletteData.。
下一部分讲解如何用RGB值来表达颜色,和怎样用PaletteData来给每个象素设定特定颜色。
颜色
类org.eclipse.swt.graphics.Color是用来管理实现RGB颜色模型的资源。
每种颜色由红色,绿色和蓝色三色素(每个都表示没有任何颜色0到全色255之间的一个整数值)组成。
ColorcyanColor=newColor(display,0,255,255);
//...CodetousetheColor
cyanColor.dispose();
SWT中存在一个便节类org.eclipse.swt.graphics.RGB把红色,绿色和蓝色结合于一个单个的对象内。
RGBcyanRGB=newRGB(0,255,255);
ColorcyanColor=newColor(display,cyanRGB);
//...CodetousetheColor
cyanColor.dispose();
当不再需要颜色实例时,颜色实例会被处理掉。
然而RGB并没有必要被处理。
这与图像和它的ImageData之间的关系类似,颜色和图像是对象使用自身基础资源的设备,而RGB和ImageData是基础模型数据。
避免创建管理通常使用的颜色实例,显示类可以使用方法Display.getSystemColor(intid).
ColorcyanColor=display.getSystemColor(SWT.COLOR_CYAN)来返回。
当一个SWT程序用Display.getSystemColor(intid)来获得颜色时,颜色不能被处理掉。
这个经验法则适合任何SWT资源:
“谁创建,谁处理”。
由上面的原则返回cyan颜色实例,因为没有明确地建立过,所以也不应该被随便处理掉。
一种颜色是如何确切呈现在显示器上的,这是由比如显示器深度解决办法等这类因素决定的。
更多关于这个和SWT颜色模型的问题详见SWT颜色模型。
PaletteData
有两种PaletteData,一个索引调色板,一个直接调色板。
PaletteData是一个象素值绘制RGB值的模型,因为调色板不代表基础资源,它们也不需要被处理。
索引调色板
索引调色板中每个像素值代表一个数值,然后通过索引调色板来决定实际颜色。
可允许索引的的象素值范围大小不超过该图像的深度。
下面的例子是创建一个深度为1位,48*48的正方形图像和一个索引调色板。
索引调色板指定
0是红色1是绿色(根据建造者RGB[]的指令)。
ImageData's非预置的像素值初始值为0(红色),2个为环
在ImageData的中央设置一个34*34的正方形图像,设定1(绿色)。
PaletteDatapaletteData=newPaletteData(
newRGB[]{newRGB(255,0,0),newRGB(0,255,0)});
ImageDataimageData=newImageData(48,48,1,paletteData);
for(intx=11;x<35;x++){
for(inty=11;y<35;y++){
imageData.setPixel(x,y,1);
}
}
Imageimage=newImage(display,imageData);
上述例子深度为1位,因此可以储存2种颜色。
当图像颜色深度增加时,调色板颜色数量同时增加。
索引调色板允许的图像深度为1,2,4,8位,深度为8位时可以提供2^8=256种可能的颜色。
还需要更高的颜色深度时(例如16,24,或者32),就必须使用直接调色板。
直接调色板
不像在索引调色板中,每个像素值对应着调色板索引中的一个颜色,直接调色板允许每个象素值直接记录红,绿和蓝三色素的组成。
直接PaletteData定义了红色,绿色和蓝色面罩。
我们把像素值移至左以使面罩的高位与颜色首字节的高位一致,这个过程要求的比特值数就是面罩数量。
例如,一24位直接调色板可分成3部份,低8位用来储存红色,中间的8位储存绿色,而高8位则储存蓝色。
红色的移动面罩是0xFF,绿色是0xFF00而蓝色是0xFF0000。
每个象素值都是24位整数中红色,绿色和蓝色的组合。
建立一个索引调色板使用
允许红色,绿色,蓝色面罩被详细说明
PaletteDatapalette=newPaletteData(0xFF,0xFF00,0xFF0000);
ImageDataimageData=newImageData(48,48,24,palette);
用之前同样的知识,代码反复说明了放置到两者中任何一个的像素坐标。
0xFF(forred)or
0xFF00(forgreen).
for(intx=0;x<48;x++){
for(inty=0;y<48;y++){
if(y>11&&y<35&&x>11&&x<35){
imageData.setPixel(x,y,0xFF00); //Setthecentertogreen
}else{
imageData.setPixel(x,y,0xFF); //andeverythingelsetored
}
}
};
Imageimage=newImage(display,imageData);
这就创建了下面这个中心绿色外围红色的图像。
因为直接调色板支持16,24和32位的颜色深度,我们可以用它设计出比仅支持最大8位深度的索引调色板更多的颜色。
24位的颜色深度可以描述高达1600万颜色(2^24)。
但是代价是更大的尺寸,因为深度为8位的索引调色板中,每个图像坐标仅占一个字节,然而一24位的直接调色板中每个图像坐标要占3字节。
当然用直接调色板和索引调色板都可以从RGB转化到像素值,反之亦然,这要使用公有方法intgetPixel(RGBrgb)andRGBgetRGB(intpixelValue)。
透明度
透明度的目的是使部分图像非不透明,因此在GUI表面画图时,原始背景是可以透过来显示的。
这是通过指定图像中某颜色是透明的做到的。
一旦绘制透明颜色的像素值,我们就用原始目的背景像素值颜色来代替调色板定义的RGB值。
对用户的影响就是无论绘制什么图像,透明像素的图像区域都只显示背景。
因此获得了透明度。
一些固定格式的图片文件,比如GIE或BMP格式,允许指定透明像素值,但是仅限索引调色板或颜色深度不大于8的图像。
当图像被直接应用在像按钮或者标签那样的控制上时,本地行为可能是透明象素被忽视并且绘制在资源指定的像素颜色里。
但是在SWT中,本机映象透明度支持包括GC在内的很多操作。
为了说明这点,下面得文件Idea.gif,颜色深度8位,白色象素(在调色板里索引255)被设置为透明象素。
下面的外壳左侧有一个标签,紧挨着一幅油画。
Idea.gif被用做
标签图,而且在画图事件中也用到了
油画。
因为标签不支持本机透明度,背景使用了原始的白色透明像素,然而画图事件中的GC反映了透明像素而灰色背景显示了穿透性。
ImageideaImage=newImageData(getClass().getResourceAsStream("Idea.gif"));
Labellabel=newLabel(shell,SWT.NONE);
label.setImage(ideaImage);
Canvascanvas=newCanvas(shell,SWT.NO_REDRAW_RESIZE);
canvas.addPaintListener(newPaintListener(){
publicvoidpaintControl(PaintEvente){
e.gc.drawImage(ideaImage,0,0);
}
});
上述例子我按自己的喜好用的自己图片,因为事实上我没有使用eclipse文章中包含的图片。
因为原始图片是JPG格式的,而JPG格式不支持透明度,所以我用图形转换工具把它转化成了GIF格式,然后再调色板中将白色像素设置为透明像素。
下面就是初始的Idea.jpg,尽管它和Idea.gif看起来一模一样,但这只是因为它画在HTML浏览器的白色背景上。
用原始JPG文件格式给我们提供了一个很好的例子来告诉我们怎样操作自身ImageData来progrmatically获得透明度效果。
ImageData类有一个公有区transparentPixel来说明一旦在ImageData实例中载入固定格式图片那个像素可以被设定为透明像素,不需要考虑文件格式是否支持透明度。
下面代码在一ImageData对象中载入图片Idea.jpg
在ImageData中设置调色板中白色像素为透明像素。
索引调色板的像素值返回白色
用getPixel(RGB)方法.操作ImageData来创建一个图像透明Idea图片,白色像素被指定为透明像素。
ImageDataideaData=newImageData(
getClass().getResourceAsStream("Idea.jpg"));
intwhitePixel=ideaData.palette.getPixel(newRGB(255,255,255));
ideaData.transparentPixel=whitePixel;
ImagetransparentIdeaImage=newImage(display,ideaData);
下一个外壳用到了新建的图像
在本机标签中同时也在绘图事件中
用油画。
窗口标签不支持本地透明度,所以依然采用白色背景,无论源图片是否含白色像素,油画的GC都采用已有的背景色,所以图片是透明的。
LabeltransparentIdeaLabel=newLabel(shell,SWT.NONE);
transparentIdeaLabel.setImage(transparentIdeaImage);
Canvascanvas=newCanvas(shell,SWT.NONE);
canvas.addPaintListener(newPaintListener(){
publicvoidpaintControl(PaintEvente){
e.gc.drawImage(transparentIdeaImage,0,0);
}
});
可以从两幅图像中的第二幅图看出(画在设置白色像素为透明像素的油画上),仍然有一些白色。
进一步的分析表明这并不算一个缺陷,但是这些地区不是纯白色的(255,255,255),而是有点返白色(例如255,254,254)。
ImageData的透明象素只能为一单个值。
这又引出了另一个有待解决问题-在ImageData里找到所有返白象素并且把他们转化成纯白色。
为此,我们将反复检查ImageData中的每个像素,把接近于白色改成纯白色。
操作ImageData
因为图片Idea.jpg没有我们想要的那么白,我们要反复检查ImageData中的每个像素,把返白色改成纯白色,然后保存为新的文件Idea_white.jpg。
实际上在SWT里做这种编程是不太可能的,但是用来向我们展示如何分析和操作ImageData这的确是一个好例子。
第一步是载入图像,然后反复分别检查每个象素的颜色。
因为Idea.jpg使用直接调色板,象素价值是一个int整数,内部包含红色,绿色和蓝色组成的面罩比特区。
可以从调色板获得这些面罩值。
ImageDataideaImageData=newImageData(
getClass().getResourceAsStream("Idea.jpg"));
intredMask=ideaImageData.palette.redMask;
intblueMask=ideaImageData.palette.blueMask;
intgreenMask=ideaImageData.palette.greenMask;
我们可以用面罩bitwiseAND看出所有象素值的颜色组成。
红组成部分是低数位,因此对应实际值(从0到255),因为占高位,所以绿色和蓝色值需要调整。
为了做调整,我们可以用>>操作符来移动颜色组成部分到右侧。
如果你正在编写一般代码做这种操作,注意直接调色板中深度24位或32位的颜色用低位存储红色组成部分,而深度16位的颜色相反,红色占高位蓝色占低位。
这个原因同Windows内部储存图像,这样创建图像时,几乎没有变换。
imageData中会反复强调两个为环。
第一个是从上到下横穿图像一次,然后
创建一个int[]来容纳每条数据线。
用方法ImageData.getPixels(intx,inty,intgetWidth,int[]pixels,intstartIndex)
每次从imageData的字节中选择一条线。
这个方法的API有些不规则,因为与其返回数据结果不如声明为空,结果像素数据加入int[]作为方法讨论通过。
像素的int[]被反复调用而且每个值都有自己的
红色,
绿色和
蓝色组成部分被选出。
我们希望的是可以判断是否该像素是返白色,如果是就把它转变成纯白色-假设所有像素的红绿组成都高于230,这是一个非常好用的规则
蓝色组成部分高于150就是返白色
int[]lineData=newint[ideaImageData.width];
for(inty=0;y ideaImageData.getPixels(0,y,width,lineData,0);
//Analyzeeachpixelvalueintheline
for(intx=0;x //Extractthered,greenandbluecomponent
intpixelValue=lineData[x];
intr=pixelValue&redShift;
intg=(pixelValue&greenShift)>>8;
intb=(pixelValue&blueShift)>>16;
if(r>230&&g>230&&b>150){
ideaImageData.setPixel(x,y,0xFFFFFF);
}
}
};
已经操作构成ImageData的未加工的字节,我们现在已经成功把返白色值改变成纯白色。
保存图像
现在既然有了ImageData,其中所有带白色象素都变为白色,并且调色板的透明度象素已经被设置为白色,我们将保存这幅图像,以便下次某个SWT程序需要纯白色的JPF时,可以直接载入文件照原样使用它。
将ImageData存到一个文件中使用类org.eclipse.swt.graphics.ImageLoader。
图像载入者有一个公开域数据输入到ImageData[]。
数据域是ImageData的一个阵列,因为这样可以用不止一个框架支持图像文件形式,比如能动的GIFs格式或者交错JPEG文件。
在接下来的动画部分会提到更多。
ImageLoaderimageLoader=newImageLoader();
imageLoader.data=newImageData[]{ideaImageData};
imageLoader.save("C:
/temp/Idea_PureWhite.jpg",SWT.IMAGE_JPEG);
完成结果展示如下:
看起来和最初的Idea.jpg没什么两样,因为我们采用的是白色背景,但是如果我们在油画板上画图,并且设置白色像素透明,就会看到期望的效果。
ImageDatapureWhiteIdeaImageData=
newImageData("C:
/temp/Idea_PureWhite.jpg");
pureWhiteIdeaImageData.transparentPixel=
pureWhiteIdeaImageData.palette.getPixel(newRGB(255,255,255));