好了现在做准备工作，你需要准备好以下几个软件：
1。EAC 095
2。Monkey Audio 397（就是所说的猴子）
3。foobar2000 077（注意：必须完全安装才行）
4。Alcohol.120 （就是所说的酒精）
5。NeroBurning
在准备好以上软件后，你开始需要了解刻录音频CD的常用方式：
1。由CD镜像直接刻录
这种方式需要有镜像文件，目前常见的有2种，一种是整盘镜像的[BIN,ISO等]（网上这种比较少），另外就是我们常见的抓轨压缩方式（APE)，镜像刻录是最理想的刻录方式，如果镜像文件做的好，用EAC刻出的CD几乎可以乱真原版。
2。用刻录软件的音频CD刻录方式刻录
以上2种方式都需要把APE文件解压为WAV格式才行（也有些安装插件后可以直接调用APE，但是不推荐这么做）
下面来说说你从网上下载的几种常见的APE情况：
A.由一个很大的 CDImage.ape 和 CDImage.cue 文件组成
B.由若干个小的*.ape 和一个 *.cue 文件组成
C.有若干个小的*.ape 而没有 CUE文件
D.由若干个小的*.ape 和一个 *.fpl 文件组成
其中ape是压缩的音频文件，cue是镜像信息文件（同时也是菜单文件），fpl只是菜单文件。
以上都明白了吧？现在我们开始就几种情况来讲解如何从APE刻录音频CD。
刻录前的首要工作：将ape格式解压成wav格式
ape转wav有2种方式：
1。用Monkey Audio转
2。用foobar2000转
ape转wav 之Monkey Audio篇（一）：打开Monkey Audio后先定工作模式为－－解压缩
ape转wav 之Monkey Audio篇（二）：点这里准备添加APE文件
wav 之Monkey Audio篇（三）：选定你要解压的APE文件
ape转wav 之Monkey Audio篇（四）：点这里开始解压
ape转wav 之Monkey Audio篇（五）：解压需要些时间，中间你可以随时终止解压
ape转wav 之Monkey Audio篇（六）：解压后你会看到得到的wav文件
ape转wav 之foobar2000篇（一）：用foobar2000打开要解压的ape文件，在文件上点右键，先这样来做转换设置
ape转wav 之foobar2000篇（二）：设置需要转换的wav格式
ape转wav 之foobar2000篇（三）：设置好后在文件上点右键，再点运行转换
ape转wav 之foobar2000篇（四）：开始转换了
ape转wav 之foobar2000篇（五）：对于只有一个APE和一个CUE文件的CD，如果只想要转其中的几个曲子，可以打开CUE文件，选中你要转的点右键。
转MP3或者其他格式也是一个道理，这种情况用foobar2000极其方便，推荐使用！
镜像刻录音频CD之 EAC篇（一）：首先用记事本打开CUE文件，检查一下，需要把 "*.ape" 改成 “*.wav"
镜像刻录音频CD之 EAC篇（二）：完后另外起名保存这个文件
镜像刻录音频CD之 EAC篇（三）：运行EAC软件，点左边下面的那个WRI图标
镜像刻录音频CD之 EAC篇（四）：出现CD编辑器界面后，点文件－》载入CUE文件
镜像刻录音频CD之 EAC篇（五）：载入刚才修改保存的CUE文件
镜像刻录音频CD之 EAC篇（六）：载入CUE文件后的界面，你这时可以检查试听一下曲子。
镜像刻录音频CD之 EAC篇（七）：确定无误后就可以刻碟了
镜像刻录音频CD之 Alcohol.120篇（一）：首先和EAC一样需要修正CUE文件，运行Alcohol.120，点镜像烧录向导
镜像刻录音频CD之 Alcohol.120篇（二）：打开修改的那个CUE文件
镜像刻录音频CD之 Alcohol.120篇（三）：选择合适的刻录速度（建议低速刻），开始刻碟
镜像刻录音频CD之 nero篇（一）：运行nero，点这里
镜像刻录音频CD之 nero篇（二）：选择文件格式，否则你看不到CUE文件
镜像刻录音频CD之 nero篇（三）：选择打开修改过的CUE文件
镜像刻录音频CD之 nero篇（四）：选择合适的刻录速度，建议低速刻录
镜像刻录音频CD之 nero篇（五）：确定无误后就可以刻碟了
散文件，无CUE文件的APE刻录CD之 nero篇（一）：此方法主要针对C,D和不规范CUE之A,B情况，也适用于自己组合曲子刻碟，首先必须将APE文件转换为WAV文件。
散文件，无CUE文件的APE刻录CD之 nero篇（二）：运行nero，点这里
散文件，无CUE文件的APE刻录CD之 nero篇（三）：添加已经准备好的WAV文件
散文件，无CUE文件的APE刻录CD之 nero篇（四）：确定无误，并且注意不要刻的太满（留出一定的空间余量），点下一步。
散文件，无CUE文件的APE刻录CD之 nero篇（五）：选择合适的刻录速度（建议低速刻），开始刻碟
最快捷刻录之foobar2000篇:用foobar2000可以直接刻录任何在播放器里播放的曲目到CD，特别适合散曲刻录。
最快捷刻录之foobar2000篇：（一）选中全部曲子，点右键，点刻录CD。
最快捷刻录之foobar2000篇：（二），刻录机放入CDR，就开始刻录了
英语信件的种类比较多，有一般信件，邀请信，推荐信等。但几乎所有信件的格式都大同小异。书写英语信件要注意下面几点：
（一） 英语书信结构、书写款式及要求
1．书信结构
英语书信结构一般有以下几个部分组成：
1）信封（envelope）。英语的信封和中文的一样，有三部分组成，即发信人地址、收信人地址和邮票。只不过英语信封的格式除了邮票所贴的位置（信封的右上角）和中文的一样外，英语信封上要写的发信人和收信人的地址和中文的大不一样。发信人的地址应写在信封的左上角，收信人的地址应写在信封偏中右偏下处，如下：
2）信头 (heading)，即写发信人的地址和日期（右上角）。
3）信内姓名地址 (inside address)，即写收信人的姓名和地址（左上角）。
4） 称呼 (salutation)，即写对收信人的尊称（一般用Dear Mr. … ,; Dear Madam Helen,; Dear Miss…,; Dear John,; Dear Professor Smith,等）。称呼直接写在收信人地址的正下方，中间空一至二行。称呼后面的标点一般只能用逗号。以上信头、信内姓名和地址三部分的结构如下：
注：如果是相当熟悉和随便的朋友之间，因为彼此都知道对方的地址，故信头和信内的地址常常省略。
5）正文 (body)，即信件内的主要内容。正文第一句句子一般和称呼之间空一至二行。
6）信尾客套语 (complimentary close)，即写信人在信的右（或左）下角，写上表示自己对收
信人一种礼貌客气的谦称。一般有Sincerely,; Sincerely yours,; Yours sincerely,; Friendly
yours,; Truly yours,; Yours truly,; Cordially yours,; Yours cordially,等。
7）信尾签名 (signature)，即亲笔签上写信人自己的姓名。如果是用打字机或电脑写的信，在写信人签名的上方，同样应该打上写信人的姓名。
除以上七个部分外，有时一些英语书信还包括：（1）附件 (Enclosure)，以Enc. 表示，如“附有。。。。。。证明”应写为Enc…Certificate；（2）再启 (Postscript)，以P.S. 表示；（3）抄送件(Carbon Copy to…)，以c.c. 表示，说明一式多份抄送其他有关人员。这些都是次要的补充部分。P.S. 主要在私人信件中使用，事务信件中应避免使用，以免造成写信人粗心大意的印象。Enc.和c.c. 大都用在商贸信函中。
2．书写款式
英语书信的款式一般有两种：齐头式 (Block Style) 和折衷式 (SemiBlock Style)。齐头式常常在商贸、官方以及一些正式的信件中使用，以显示信件内容的严肃性，真实性，
可靠性。而折衷式则显的比较随便，主要用于家人、朋友、私人之间来往的信件。如果两人之间不是第一次通信，相互比较了解，可以省略信内的双方地址。
以下分别介绍齐头式和折衷式信件两种款式。
A: 齐头式信件款式：
（ 范文 1。 ）
注：用齐头式信件写信，其正文与称呼之间空一至二行。每段的第一句句子不需要空
格，但段与段之间需要空一至二行。齐头式信件的信尾客套话和签名可以有两种款式。第一种写在左下方，这是最常用也是最正式的。另外也可以写在右下方，这种形式则表示写信人与收信人之间的关系比较熟悉随便。下面是另一种齐头式信件的格式。
齐头式信件款式：
（范文 2。）
B: 折衷式信件款式：
用折衷式书写信件，其正文与称呼之间空一至二行。第一段第一句的第一个单词必须在Dear称呼的直接下面。以后每段开头都要与第一段第一个字对齐。信尾的客套话和签名都写在右下方。朋友之间写信一般都使用折衷式，而且称呼与正文之间一般不空行。具体款式和要求参见后面的一些信件。
以下是一封折衷式信件。
3．信件书写要求：
写英语信件一般可以使用打字机、电脑，朋友之间比较随便的信件也可以用钢笔、圆珠笔甚至彩色笔，但不宜用铅笔。不管你用什么形式书写，一些重要的信件，签名处必须用深蓝色或黑色墨水笔签名。
（二）各类常用信件
1）感谢信
2）祝贺信
3）邀请信
4）一般信件
5）商业信件
6）求学信
7）出国留学推荐信 ( Recommendation Letter for Studying Abroad )
随着我国出国留学生日年增多一般，大部分学生需要在出国前让自己的老师、导师或领导写一份出国推荐信，从而可以在信中告知对方学校申请人的学历、能力、为人处世等方面的情况。如果推荐信是写给对方某某人的，开头用 Dear… ，如果是写给对方单位或学校的，则开头可以用To whom it may concern, 或To Whom It May Concern,（意为：有关负责人）。
以下是一封出国留学推荐信：
归根到底,首先是matlab自己默认没有中文字体。其次，Magic Linux的java设置也有问题。所以,matlab的中文显示问题的解决要有两个步骤:
如果您的 java 程序运行不正常，请检查 /etc/profile.d/javaprofile.sh 文件中的设置是否正确
#!/bin/sh #java settings JDK_VERSION=jre1.5.0_05 JAVA_HOME=/usr/java/$JDK_VERSION CLASSPATH=$JAVA_HOME/lib/rt.jar:. JAVA_FONTS=/usr/share/fonts:/usr/share/fonts/ttf/zh_CN PATH=$PATH:$JAVA_HOME/bin export JDK_VERSION JAVA_HOME CLASSPATH JAVA_FONTS PATH 
简单的方法：
1 .建立目录：$JAVA_HOME/jre/lib/fonts/fallback
2. 复制中文字体到刚才建立的目录中，或者在这个目录中建立到中文字体的链接
复杂的方法：
Sun公司的JRE(JAVA运行库)1.5.0版采用的字体设置方案跟1.4.2版的相去甚远。如果设置不当，Java程序中的中文会表现为方格。
本文给出了一般性的字体设置方法，并且在最后给出了本机测试通过的字体配置文件以供下载。
首先介绍一下其字体配置文件的加载方案。其加载顺序为（JavaHome指JRE的根目录，下同）：
JavaHome/lib/fontconfig.OS.Version.properties JavaHome/lib/fontconfig.OS.Version.bfc JavaHome/lib/fontconfig.OS.properties JavaHome/lib/fontconfig.OS.bfc JavaHome/lib/fontconfig.Version.properties JavaHome/lib/fontconfig.Version.bfc JavaHome/lib/fontconfig.properties JavaHome/lib/fontconfig.bfc
其中，OS字段可以是：
Windows： “98″, “2000″, “Me”, “XP”, “2003″。 Solaris：空。 Linux： “Sun”, “RedHat”, “Turbo”, “SuSE”。
而Version字段指该OS的版本号。
默认如果存在$JavaHome/lib/fontconfig.properties，则该文件具有绝对优先权做为JAVA的字体配置文件。
在这些配置文件中，仅.properties文件是文本文件。其格式跟JRE1.4.2版的不同。文件分为几段，并在每段开始时标明。我们需要关注的仅有两段：Component Font Mappings和Search Sequences。
前者指定字体，后者指定要使用的properties的搜索顺序。知道了这些，配置起来就简单了。
首先，设置字体文件，一般来说，Slackware 系统的字体配置文件在/etc/fonts/fonts.conf 里面设置，我比较习惯将额外的中文字体放在 /usr/share/fonts下面，为了节约空间，在JRE的字体目录JavaHome/lib/fonts下建立一个符号连接，指向我用的中文字体，（比如，宋体Simsun.ttf）：
ln s /usr/share/fonts/simsun.ttf simsun.ttf
然后运行字体库生成命令: mkfontscale，生成需要的字体库文件fonts.dir：
JavaHome/lib/fonts# mkfontscale JavaHome/lib/fonts# mv fonts.scale fonts.dir
然后，转到目录JavaHome/lib下，随便找一个.properties.src文件，用文本编辑器打开，并编辑如下：
# Copyright 2003 Sun Microsystems, Inc. All rights reserved. # # Version version=1 # Component Font Mappings serif.plain.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 serif.bold.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 serif.italic.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 serif.bolditalic.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 sansserif.plain.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 sansserif.bold.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 sansserif.italic.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 sansserif.bolditalic.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 monospaced.plain.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 monospaced.bold.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 monospaced.italic.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 monospaced.bolditalic.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 dialog.plain.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 dialog.bold.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 dialog.italic.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 dialog.bolditalic.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 dialoginput.plain.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 dialoginput.bold.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 dialoginput.italic.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 dialoginput.bolditalic.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 dialoginput.bolditalic.zh1=miscsimsunmediumrnormal0000p0gb18030.20000 # Search Sequences sequence.allfonts=zh1 # Exclusion Ranges # Font File Names # AWT X11 font paths 
上面这个文件中最重要的是字体名，也就是：
miscsimsunmediumrnormal0000p0gb18030.20000
这个东西，你可以根据fonts.dir里面的内容，选取一个合适的中文字体使用。
然后按照上面所述的文件名格式保存在这个目录下。如Redhat系统的就保存为fontconfig.RedHat.properties， WindowsXP的就保存为fontconfig.XP.properties，不知道自己系统是什么的，就直接保存为 fontconfig.properties。
现在，启动Java程序看看，漂亮的JRE1.5的中文界面是不是出来了？
复制/usr/java/j2re/lib/fontconfig.properties到.../matlab7/sys/java/jre/glnx86/jre/lib 目录下，覆盖原来的fontconfig.properties文件。
版权提示：本条目介绍的方法可能会引起版权方面的纠纷，请小心使用，并注意自行承担使用本条目所述方法的后果！
Windows的中文字体漂亮一些，所以您可以右键>动作>安装，把以C:\windows\Fonts下simsum.ttc、tahoma.ttf、tahomabd.ttf及其它自己喜欢的字体安装到系统中，任意窗口按 F4 运行终端窗口执行 fccache fv 启动matlab，在File/Preferences..菜单里面修改font，选择自己喜欢的中文字体了。
Many image processing tasks and even file type conversions, say from 32 bitperpixel to 8 bitperpixel can be speeded up by accessing the pixel data array directly, rather than relying on GetPixel and SetPixel or other methods.
You will be aware that .NET is a managed code system which most often uses managed data so it's not often that we need to gain access to bytes stored in memory anymore however, image manipulation is one of the few times when managed data access is just too slow and so we need to delve once again into the knotty problems of finding the data and manipulating it.
Before I start on the subject in hand, I'll just remind you that the methods used to access any unmanaged data will be different depending on the language in which your program is written. C# developers have the opportunity, via the unsafe keyword and use of pointers, to access data in memory directly. Visual basic programmers should access such data through the Marshal class methods which may also show a small performance loss.
The Bitmap class provides the LockBits and corresponding UnlockBits methods which enable you to fix a portion of the bitmap pixel data array in memory, access it directly and finally replace the bits in the bitmap with the modified data. LockBits returns a BitmapData class that describes the layout and position of the data in the locked array.
The BitmapData class contains the following important properties;
The relationship of Scan0 and Stride to the array in memory is shown in figure1.
Figure 1: The basic layout of a locked bitmap array
The Stride property, as shown in figure 1, holds the width of one row in bytes. The size of a row however may not be an exact multiple of the pixel size because for efficiency, the system ensures that the data is packed into rows that begin on a four byte boundary and are padded out to a multiple of four bytes. This means for example that a 24 bit per pixel image 17 pixels wide would have a stride of 52. The used data in each row would take up 3*17 = 51 bytes and the padding of 1 byte would expand each row to 52 bytes or 13*4 bytes. A 4BppIndexed image of 17 pixels wide would have a stride of 12. Nine of the bytes, or more properly eight and a half, would contain data and the row would be padded out with a further 3 bytes to a 4 byte boundary.
The data carrying portion of the row, as has been suggested above, is laid out according to the pixel format. A 24 bit per pixel image containing RGB data would have a new pixel every 3 bytes, a 32 bit per pixel RGBA every four bytes. Pixel formats that contain more than one pixel per byte, such as the 4 bit per pixel Indexed and 1 bit per pixel indexed, have to be processed carefully so that the pixel required is not confused with it's neigbour pixels in the same byte.
Because the stride is the width of a row, to index any given row or Y coordinate you can multiply the stride by the Y coordinate to get the beginning of a particular row. Finding the correct pixel within the row is possibly more difficult and depends on knowing the layout of the pixel formats. The following examples show how to access a particular pixel for a given pixel format.
Format32BppArgb Given X and Y coordinates, the address of the first element in the pixel is Scan0+(y * stride)+(x*4). This Points to the blue byte. The following three bytes contain the green, red and alpha bytes.
Format24BppRgb Given X and Y coordinates, the address of the first element in the pixel is Scan0+(y*Stride)+(x*3). This points to the blue byte which is followed by the green and the red.
Format8BppIndexed Given the X and Y coordinates the address of the byte is Scan0+(y*Stride)+x. This byte is the index into the image palette.
Format4BppIndexed Given X and Y coordinates the byte containing the pixel data is calculated as Scan0+(y*Stride)+(x/2). The corresponding byte contains two pixels, the upper nibble is the leftmost and the lower nibble is the rightmost of two pixels. The four bits of the upper and lower nibble are used to select the colour from the 16 colour palette.
Format1BppIndexed Given the X and Y coordinates, the byte containing the pixel is calculated by Scan0+(y*Stride)+(x/8). The byte contains 8 bits, each bit is one pixel with the leftmost pixel in bit 8 and the rightmost pixel in bit 0. The bits select from the two entry colour palette.
For pixel formats with one or more bytes per pixel, the formula is simple and can be accomplished by looping through all Y and X values in order. The code in the following listings sets the blue component of a 32 bit per pixel image to 255. In both cases bm is a bitmap previously created.
BitmapData bmd=bm.LockBits(new Rectangle(0, 0, 10, 10), System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat);
int PixelSize=4;
for(int y=0; y
{
byte* row=(byte *)bmd.Scan0+(y*bmd.Stride);
for(int x=0; x
{
row[x*PixelSize]=255;
}
}
In VB this operation would be treated a little differently because VB has no knowledge of pointers and requires the use of the marshal class to access unmanaged data.
Dim x As Integer
Dim y As Integer
Dim PixelSize As Integer = 4
Dim bmd As BitmapData = bm.LockBits(new Rectangle(0, 0, 10, 10), System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat)
For y = 0 To bmd.Height  1
For x = 0 To bmd.Width  1
Marshal.WriteByte(bmd.Scan0, (bmd.Stride * y) + (4 * x) , 255)
Next
Next
The Format4BppIndexed and Format1BppIndexed pixel formats mentioned earlier both have more than one pixel stored in a byte. In such cases, it's up to you to ensure that changing the data for one pixel does not effect the other pixel or pixels held in that byte.
The method for indexing a 1 bit per pixel image is shown in the GDI+ FAQ article "Converting an RGB image to 1 bitperpixel monochrome." It relies on using bitwise logical operations And and Or to reset or set specific bits in the byte. After using the formula shown above for 1 bit per pixel images, the lower 3 bits of the X coordinate is used to select the bit required. The listings below show this process in C# and VB. In both examples bmd is a bitmap data extracted from a 1 bit per pixel image.
C# code uses pointers and requires compiling with unsafe code
byte* p=(byte*)bmd.Scan0.ToPointer();
int index=y*bmd.Stride+(x>>3);
byte mask=(byte)(0x80>>(x&0x7));
if(pixel)
p[index]=mask;
else
p[index]&=(byte)(mask^0xff);
VB code uses the marshal class
Dim mask As Byte = 128 >> (x And 7)
Dim offset As Integer = (y * bmd.Stride) + (x >> 3)
Dim currentPixel As Byte = Marshal.ReadByte(bmd.Scan0, offset)
If pixel = True Then
Marshal.WriteByte(bmd.Scan0, offset, currentPixel Or mask)
Else
Marshal.WriteByte(bmd.Scan0, offset, CByte(currentPixel And (mask Xor 255)))
End If
Note, it's quite valid to use the Marshal class from C# code. I used pointers because it offers the best performance.
Accessing individual pixels in a 4 bit per pixel image is handled in a similar manner. The upper and lower nibble of the byte must be dealt with separately and changing the contents of the odd X pixels should not effect the even X pixels. The code below shows how to perform this in C# and VB.
C#
int offset = (y * bmd.Stride) + (x >> 1);
byte currentByte = ((byte *)bmd.Scan0)[offset];
if((x&1) == 1)
{
currentByte &= 0xF0;
currentByte = (byte)(colorIndex & 0x0F);
}
else
{
currentByte &= 0x0F;
currentByte = (byte)(colorIndex << 4);
}
((byte *)bmd.Scan0)[offset]=currentByte;
VB
Dim offset As Integer = (y * bmd.Stride) + (x >> 1)
Dim currentByte As Byte = Marshal.ReadByte(bmd.Scan0, offset)
If (x And 1) = 1 Then
currentByte = currentByte And &HF0
currentByte = currentByte Or (colorIndex And &HF)
Else
currentByte = currentByte And &HF
currentByte = currentByte Or (colorIndex << 4)
End If
Marshal.WriteByte(bmd.Scan0, offset, currentByte)
The LockBits method takes a rectangle which may be the same size or smaller than the image being processed, a PixelFormat which is usually the same as that of the image being processed and a ImageLockMode value that specifies whether the data is readonly, writeonly, readwrite or a user allocated buffer. This last option cannot be used from C# or VB because the method overload for LockBits that specifies a user buffer is not included in the GDI+ managed wrapper.
It is very important that when all operations are complete the BitmapData is put back into the bitmap with the UnlockBits method. The snippet of code below illustrates this.
Dim bmd As BitmapData = bm.LockBits(New Rectangle(0, 0, 10, 10), ImageLockMode.ReadWrite, bm.PixelFormat)
' do operations here
bm.UnlockBits(bmd)
That just about covers the aspects of accessing the most popular and most difficult pixel formats directly. Using these techniques instead of the GetPixel and SetPixel methods provided by Bitmap will show a marked performance boost to your image processing and image format conversion routines.
Copyright Robert W. Powell 2003. All rights reserved.
]]>For some reason Microsoft made it pretty hard to work with anything but 24bit images. This is even though they provide you with several pixel formats, but no way of setting and getting the values of a pixel. If you use the SetPixel(x,y) or GetPixel(x,y) methods, your application will fail. There are plenty of articles and blogs on the Internet on how to do direct access on 1bit and 24bit, but I wasn't able to find anything on 8bit.
This article will cover some of the basics on how to access 8 bit greyscale or indexed images, by accessing the bitmapdata directly in memory. This also has the benefit of being much faster than the Set/GetPixel methods provided by the .NET Framework.
Before we can access the memory directly, we must lock its place in memory. We can do this by calling the Bitmap.LockBits() method:
BitmapData bmd = myBitmap.LockBits(new Rectangle(0, 0, myBitmap.Width, myBitmap.Height),
ImageLockMode.ReadWrite, myBitmap.PixelFormat);
Likewise when we are done using the BitmapData, remember to unlock the data:
myBitmap.UnlockBits(bmd);
Now we need a method that can access the BitmapData. Lets make our own SetPixel and GetPixel method. Here we assume that we are dealing with 8bit pixels. We also add the 'unsafe' keyword since direct memory access isn't thread safe. I won't cover the Stride and Scan0 values. Bob Powell has a nice article on this.
public unsafe void SetPixel(int x, int y, byte c) { byte* p = (byte *)bmd.Scan0.ToPointer(); int offset=y*bmd.Stride+(x); p[offset] = c; } public unsafe Byte GetPixel(int x, int y) { byte* p = (byte *)bmd.Scan0.ToPointer(); int offset=y*bmd.Stride+x; return p[offset]; }
It is worth noting that GetPixel only returns a byte and not a color. The byte represents a number between 0 and 255. Each of the values is actually an index to a color palette. The palette could specify that for instance index 0 is black, index 1 is red, index 3 is blue etc. If you want a greyscale image, we can override the color palette. Let's set index 0 to black, index 255 to white, and linearly distribute the grayscale in between.
public static void SetGrayscalePalette(Bitmap b)
{
ColorPalette pal = b.Palette;
for(int i = 0; i < 256; i++)
pal.Entries[i] = Color.FromArgb( 255, i, i, i );
b.Palette = pal;
}
You can easily override this palette to specify other than grayscale images.
We can likewise create a function that can convert an index to a System.Drawing.Color. If you are working with a grayscale image, there is probably no need for this.
public System.Drawing.Color GetColorFromIndex(byte c) { return = myBitmap.Palette.Entries[c]; }
Now let's put it all together into an easytouse 8bit image access class. Remember to allow unsafe code blocks before compiling.
using System; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; namespace ImageProc { ////// Class used for direct memory access to 8bit grayscale images /// public class Image8Bit { private BitmapData bmd; private Bitmap b; ////// Locks an 8bit image in memory for fast get/set pixel functions. /// Remember to Dispose object to release memory. /// /// Bitmap reference public Image8Bit (Bitmap bitmap) { if(bitmap.PixelFormat!=System.Drawing.Imaging.PixelFormat.Format8bppIndexed) throw(new System.Exception("Invalid PixelFormat. 8 bit indexed required")); b = bitmap; //Store a private reference to the bitmap bmd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),
ImageLockMode.ReadWrite, b.PixelFormat); } ////// Releases memory /// public void Dispose() { b.UnlockBits(bmd); } ////// Gets color of an 8bitpixel /// /// Row /// Column ///Color of pixel public unsafe System.Drawing.Color GetPixel(int x, int y) { byte* p = (byte *)bmd.Scan0.ToPointer(); //always assumes 8 bit per pixels int offset=y*bmd.Stride+x; return GetColorFromIndex(p[offset]); } ////// Sets color of an 8bitpixel /// /// Row /// Column /// Color index public unsafe void SetPixel(int x, int y, byte c) { byte* p = (byte *)bmd.Scan0.ToPointer(); //always assumes 8 bit per pixels int offset=y*bmd.Stride+(x); p[offset] = c; } ////// Sets the palette for the referenced image to Grayscale /// public void MakeGrayscale() { SetGrayscalePalette(this.b); } ////// Sets the palette of an image to grayscales (0=black, 255=white) /// /// Bitmap to set palette on public static void SetGrayscalePalette(Bitmap b) { ColorPalette pal = b.Palette; for(int i = 0; i < 256; i++) pal.Entries[i] = Color.FromArgb( 255, i, i, i ); b.Palette = pal; } private System.Drawing.Color GetColorFromIndex(byte c) { return = b.Palette.Entries[c]; } } }
Many image processing tasks and even file type conversions, say from 32 bitperpixel to 8 bitperpixel can be speeded up by accessing the pixel data array directly, rather than relying on GetPixel and SetPixel or other methods.
You will be aware that .NET is a managed code system which most often uses managed data so it's not often that we need to gain access to bytes stored in memory anymore however, image manipulation is one of the few times when managed data access is just too slow and so we need to delve once again into the knotty problems of finding the data and manipulating it.
Before I start on the subject in hand, I'll just remind you that the methods used to access any unmanaged data will be different depending on the language in which your program is written. C# developers have the opportunity, via the unsafe keyword and use of pointers, to access data in memory directly. Visual basic programmers should access such data through the Marshal class methods which may also show a small performance loss.
The Bitmap class provides the LockBits and corresponding UnlockBits methods which enable you to fix a portion of the bitmap pixel data array in memory, access it directly and finally replace the bits in the bitmap with the modified data. LockBits returns a BitmapData class that describes the layout and position of the data in the locked array.
The BitmapData class contains the following important properties;
The relationship of Scan0 and Stride to the array in memory is shown in figure1.
Figure 1: The basic layout of a locked bitmap array
The Stride property, as shown in figure 1, holds the width of one row in bytes. The size of a row however may not be an exact multiple of the pixel size because for efficiency, the system ensures that the data is packed into rows that begin on a four byte boundary and are padded out to a multiple of four bytes. This means for example that a 24 bit per pixel image 17 pixels wide would have a stride of 52. The used data in each row would take up 3*17 = 51 bytes and the padding of 1 byte would expand each row to 52 bytes or 13*4 bytes. A 4BppIndexed image of 17 pixels wide would have a stride of 12. Nine of the bytes, or more properly eight and a half, would contain data and the row would be padded out with a further 3 bytes to a 4 byte boundary.
The data carrying portion of the row, as has been suggested above, is laid out according to the pixel format. A 24 bit per pixel image containing RGB data would have a new pixel every 3 bytes, a 32 bit per pixel RGBA every four bytes. Pixel formats that contain more than one pixel per byte, such as the 4 bit per pixel Indexed and 1 bit per pixel indexed, have to be processed carefully so that the pixel required is not confused with it's neigbour pixels in the same byte.
Because the stride is the width of a row, to index any given row or Y coordinate you can multiply the stride by the Y coordinate to get the beginning of a particular row. Finding the correct pixel within the row is possibly more difficult and depends on knowing the layout of the pixel formats. The following examples show how to access a particular pixel for a given pixel format.
Format32BppArgb Given X and Y coordinates, the address of the first element in the pixel is Scan0+(y * stride)+(x*4). This Points to the blue byte. The following three bytes contain the green, red and alpha bytes.
Format24BppRgb Given X and Y coordinates, the address of the first element in the pixel is Scan0+(y*Stride)+(x*3). This points to the blue byte which is followed by the green and the red.
Format8BppIndexed Given the X and Y coordinates the address of the byte is Scan0+(y*Stride)+x. This byte is the index into the image palette.
Format4BppIndexed Given X and Y coordinates the byte containing the pixel data is calculated as Scan0+(y*Stride)+(x/2). The corresponding byte contains two pixels, the upper nibble is the leftmost and the lower nibble is the rightmost of two pixels. The four bits of the upper and lower nibble are used to select the colour from the 16 colour palette.
Format1BppIndexed Given the X and Y coordinates, the byte containing the pixel is calculated by Scan0+(y*Stride)+(x/8). The byte contains 8 bits, each bit is one pixel with the leftmost pixel in bit 8 and the rightmost pixel in bit 0. The bits select from the two entry colour palette.
For pixel formats with one or more bytes per pixel, the formula is simple and can be accomplished by looping through all Y and X values in order. The code in the following listings sets the blue component of a 32 bit per pixel image to 255. In both cases bm is a bitmap previously created.
BitmapData bmd=bm.LockBits(new Rectangle(0, 0, 10, 10), System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat);
int PixelSize=4;
for(int y=0; y
{
byte* row=(byte *)bmd.Scan0+(y*bmd.Stride);
for(int x=0; x
{
row[x*PixelSize]=255;
}
}
In VB this operation would be treated a little differently because VB has no knowledge of pointers and requires the use of the marshal class to access unmanaged data.
Dim x As Integer
Dim y As Integer
Dim PixelSize As Integer = 4
Dim bmd As BitmapData = bm.LockBits(new Rectangle(0, 0, 10, 10), System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat)
For y = 0 To bmd.Height  1
For x = 0 To bmd.Width  1
Marshal.WriteByte(bmd.Scan0, (bmd.Stride * y) + (4 * x) , 255)
Next
Next
The Format4BppIndexed and Format1BppIndexed pixel formats mentioned earlier both have more than one pixel stored in a byte. In such cases, it's up to you to ensure that changing the data for one pixel does not effect the other pixel or pixels held in that byte.
The method for indexing a 1 bit per pixel image is shown in the GDI+ FAQ article "Converting an RGB image to 1 bitperpixel monochrome." It relies on using bitwise logical operations And and Or to reset or set specific bits in the byte. After using the formula shown above for 1 bit per pixel images, the lower 3 bits of the X coordinate is used to select the bit required. The listings below show this process in C# and VB. In both examples bmd is a bitmap data extracted from a 1 bit per pixel image.
C# code uses pointers and requires compiling with unsafe code
byte* p=(byte*)bmd.Scan0.ToPointer();
int index=y*bmd.Stride+(x>>3);
byte mask=(byte)(0x80>>(x&0x7));
if(pixel)
p[index]=mask;
else
p[index]&=(byte)(mask^0xff);
VB code uses the marshal class
Dim mask As Byte = 128 >> (x And 7)
Dim offset As Integer = (y * bmd.Stride) + (x >> 3)
Dim currentPixel As Byte = Marshal.ReadByte(bmd.Scan0, offset)
If pixel = True Then
Marshal.WriteByte(bmd.Scan0, offset, currentPixel Or mask)
Else
Marshal.WriteByte(bmd.Scan0, offset, CByte(currentPixel And (mask Xor 255)))
End If
Note, it's quite valid to use the Marshal class from C# code. I used pointers because it offers the best performance.
Accessing individual pixels in a 4 bit per pixel image is handled in a similar manner. The upper and lower nibble of the byte must be dealt with separately and changing the contents of the odd X pixels should not effect the even X pixels. The code below shows how to perform this in C# and VB.
C#
int offset = (y * bmd.Stride) + (x >> 1);
byte currentByte = ((byte *)bmd.Scan0)[offset];
if((x&1) == 1)
{
currentByte &= 0xF0;
currentByte = (byte)(colorIndex & 0x0F);
}
else
{
currentByte &= 0x0F;
currentByte = (byte)(colorIndex << 4);
}
((byte *)bmd.Scan0)[offset]=currentByte;
VB
Dim offset As Integer = (y * bmd.Stride) + (x >> 1)
Dim currentByte As Byte = Marshal.ReadByte(bmd.Scan0, offset)
If (x And 1) = 1 Then
currentByte = currentByte And &HF0
currentByte = currentByte Or (colorIndex And &HF)
Else
currentByte = currentByte And &HF
currentByte = currentByte Or (colorIndex << 4)
End If
Marshal.WriteByte(bmd.Scan0, offset, currentByte)
The LockBits method takes a rectangle which may be the same size or smaller than the image being processed, a PixelFormat which is usually the same as that of the image being processed and a ImageLockMode value that specifies whether the data is readonly, writeonly, readwrite or a user allocated buffer. This last option cannot be used from C# or VB because the method overload for LockBits that specifies a user buffer is not included in the GDI+ managed wrapper.
It is very important that when all operations are complete the BitmapData is put back into the bitmap with the UnlockBits method. The snippet of code below illustrates this.
Dim bmd As BitmapData = bm.LockBits(New Rectangle(0, 0, 10, 10), ImageLockMode.ReadWrite, bm.PixelFormat)
' do operations here
bm.UnlockBits(bmd)
That just about covers the aspects of accessing the most popular and most difficult pixel formats directly. Using these techniques instead of the GetPixel and SetPixel methods provided by Bitmap will show a marked performance boost to your image processing and image format conversion routines.
]]>最近的工作,需要对图像进行处理,查了一下资料,GDI+就可以满足要求,所以就用它了.
下面是开始的设置,方便有这个需求的朋友使用. :)
GDI+是什么?
GDI+ 是面向 C/C++ 程序员的基于类的应用程序编程接口 (API)。它使应用程序可以
将图形和格式化文本同时用于视频显示和打印机。GDI+ 代表应用程序与设备驱动程序
进行交互。GDI+ 还支持 64 位 Windows 操作系统。
vc6中如何安装?
一种方式是安装.net platform sdk,里面就会包含GDI+的相关库文件和头文件
若是不想为了GDI+就安装.NET PLATFORM SDK,那就可以下载单独的库文件和头文件,
下载地址:http://www.codersource.net/samples/mfcgdiplus.zip下载后,将文件解
压缩到某个目录,然后将VC的include和lib目录分别指向刚才的目录中的lib和include
vc6中如何使用?
建立一个MFC工程,将以下代码放到stdafx.h中
#pragma comment(lib, "gdiplus.lib") //注意,要保证vc路径的lib中,能够找到这个文件
#define ULONG_PTR ULONG
#include
using namespace Gdiplus;
然后增加app类中的变量:
GdiplusStartupInput m_gdiplusStartupInput;
ULONG_PTR m_pGdiToken;
在InitInstance函数中,增加代码
GdiplusStartup(&m_pGdiToken,&m_gdiplusStartupInput,NULL);
增加ExitInstance函数中,增加以下代码
GdiplusShutdown(m_pGdiToken);
此时编译应该能够通过,执行前,检查一下GDIPLUS.DLL是否在系统目录或当前目录
以后的工作就是你的了! :)
参考:
http://www.codersource.net/mfc_gdi_plus_common_issues.html
http://msdn.microsoft.com/library/enus/gdicpp/gdiplus/gdiplus.asp
Download demo source code  95 Kb
This article provides source code in order to read and display JPEG and GIF pictures using no thirdparty library at all. Both MFC and nonMFC source code is provided as to fit the largest requirements.
Why such a thing in first place? Simple, I am used to have a dependency on a GIF read/write thirdparty library and a JPEG read/write thirdparty library whenever I have to use nonflat *.BMP files. Regardless the GIF licensing issues, which have ended up in the united states since june 2003, I have always relied on thirdparties because of the lack of such thing along with the WIN32 API. Wrong was I. OLE/COM provides an interface I have even played with last year, and the MSDN documentation is kept so outofsync that it doesn't even mention what the IPicture interface really supports.
So, while MSDN limits the capabilities of the IPicture interface to BMP, ICO, CUR and WMF pics, actually this interface supports nonanimated GIF as well as JPEG pics. In addition, the interface manages the rendering by passing it a device context.
Igor, someone I have met in codeproject forums, was kind enough to show me a link[^] to an existing MFC sample implementation for it, basically a single class called CPicture
. So I decided that, because my needs are such that I don't want any MFC in my code, I have rewritten the CPicture class with raw WIN32/GDI calls. And that's what I am showing here.
In the remainder of this article, I provide the code for the WIN32/GDI implementation, then a sample code to use it. This is followed by the reproduced MFC implementation from PaulDiLascia, and then again a sample showing how to use it.
A pic needs to be inserted in the .rc file. How it works is as follows : open the .rc editor, righclick on Resources, and choose Import. In the open dialog, select the *.* file types in order to show .gif and .jpeg files, then choose one. At insertion time, VisualStudio prompts for a category name since obviously those file extensions are unsupportedi in version 6.0. Enter IMAGE, and then enter a unique id to reference the pic. Please note that the source code explicitely references the IMAGE category. Make sure to get the code sync with it.
Picture.h CUT HERE #pragma once ////////////////// // Picture objectencapsulates IPicture // class CPicture { public: CPicture(); ~CPicture(); // Load frm various sosurces BOOL Load(HINSTANCE hInst, UINT nIDRes); BOOL Load(LPCTSTR pszPathName); BOOL Load(IStream* pstm); // render to device context BOOL Render(HDC dc, RECT* rc, LPCRECT prcMFBounds=NULL) const; SIZE GetImageSize(HDC dc=NULL) const; operator IPicture*() { return m_spIPicture; } void GetHIMETRICSize(OLE_XSIZE_HIMETRIC& cx, OLE_YSIZE_HIMETRIC& cy) const { cx = cy = 0; const_cast(this)>m_hr = m_spIPicture>get_Width(&cx); const_cast (this)>m_hr = m_spIPicture>get_Height(&cy); } void Free() { if (m_spIPicture) { m_spIPicture.Release(); } } protected: void SetHIMETRICtoDP(HDC hdc, SIZE* sz) const; CComQIPtr m_spIPicture; // ATL smart pointer to IPicture HRESULT m_hr; // last error code }; Picture.cpp CUT HERE #include "stdafx.h" #include #include "Picture.h" #define HIMETRIC_INCH 2540 // HIMETRIC units per inch //////////////////////////////////////////////////////////////// // CPicture implementation // CPicture::CPicture() { } CPicture::~CPicture() { } ////////////////// // Load from resource. Looks for "IMAGE" type. // BOOL CPicture::Load(HINSTANCE hInst, UINT nIDRes) { // find resource in resource file HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nIDRes), "IMAGE"); // type if ( !hRsrc ) return FALSE; // load resource into memory DWORD len = ::SizeofResource(hInst, hRsrc); HGLOBAL hResData = ::LoadResource(hInst, hRsrc); if ( !hResData ) return FALSE; HGLOBAL hGlobal = ::GlobalAlloc(GMEM_MOVEABLE  GMEM_NODISCARD, len); if ( !hGlobal ) { ::FreeResource(hResData); return FALSE; } char* pDest = reinterpret_cast ( ::GlobalLock(hGlobal) ); char* pSrc = reinterpret_cast ( ::LockResource(hResData) ); if (!pSrc  !pDest) { ::GlobalFree(hGlobal); ::FreeResource(hResData); return FALSE; } ::CopyMemory(pDest,pSrc,len); ::FreeResource(hResData); ::GlobalUnlock(hGlobal); // don't delete memory on object's release IStream* pStream = NULL; if ( ::CreateStreamOnHGlobal(hGlobal,FALSE,&pStream) != S_OK ) { ::GlobalFree(hGlobal); return FALSE; } // create memory file and load it BOOL bRet = Load(pStream); ::GlobalFree(hGlobal); return bRet; } ////////////////// // Load from path name. // BOOL CPicture::Load(LPCTSTR pszPathName) { HANDLE hFile = ::CreateFile(pszPathName, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if ( !hFile ) return FALSE; DWORD len = ::GetFileSize( hFile, NULL); // only 32bit of the actual file size is retained if (len == 0) return FALSE; HGLOBAL hGlobal = ::GlobalAlloc(GMEM_MOVEABLE  GMEM_NODISCARD, len); if ( !hGlobal ) { ::CloseHandle(hFile); return FALSE; } char* lpBuffer = reinterpret_cast ( ::GlobalLock(hGlobal) ); DWORD dwBytesRead = 0; while ( ::ReadFile(hFile, lpBuffer, 4096, &dwBytesRead, NULL) ) { lpBuffer += dwBytesRead; if (dwBytesRead == 0) break; dwBytesRead = 0; } ::CloseHandle(hFile); ::GlobalUnlock(hGlobal); // don't delete memory on object's release IStream* pStream = NULL; if ( ::CreateStreamOnHGlobal(hGlobal,FALSE,&pStream) != S_OK ) { ::GlobalFree(hGlobal); return FALSE; } // create memory file and load it BOOL bRet = Load(pStream); ::GlobalFree(hGlobal); return bRet; } ////////////////// // Load from stream (IStream). This is the one that really does it: call // OleLoadPicture to do the work. // BOOL CPicture::Load(IStream* pstm) { Free(); HRESULT hr = OleLoadPicture(pstm, 0, FALSE, IID_IPicture, (void**)&m_spIPicture); return hr == S_OK; } ////////////////// // Render to device context. Covert to HIMETRIC for IPicture. // // prcMFBounds : NULL if dc is not a metafile dc // BOOL CPicture::Render(HDC dc, RECT* rc, LPCRECT prcMFBounds) const { if ( !rc  (rc>right == rc>left && rc>bottom == rc>top) ) { SIZE sz = GetImageSize(dc); rc>right = sz.cx; rc>bottom = sz.cy; } long hmWidth,hmHeight; // HIMETRIC units GetHIMETRICSize(hmWidth, hmHeight); m_spIPicture>Render(dc, rc>left, rc>top, rc>right  rc>left, rc>bottom  rc>top, 0, hmHeight, hmWidth, hmHeight, prcMFBounds); return TRUE; } ////////////////// // Get image size in pixels. Converts from HIMETRIC to device coords. // SIZE CPicture::GetImageSize(HDC dc) const { SIZE sz = {0,0}; if (!m_spIPicture) return sz; LONG hmWidth, hmHeight; // HIMETRIC units m_spIPicture>get_Width(&hmWidth); m_spIPicture>get_Height(&hmHeight); sz.cx = hmWidth; sz.cy = hmHeight; if ( dc == NULL ) { HDC dcscreen = ::GetWindowDC(NULL); SetHIMETRICtoDP(dcscreen,&sz); // convert to pixels } else { SetHIMETRICtoDP(dc,&sz); } return sz; } void CPicture::SetHIMETRICtoDP(HDC hdc, SIZE* sz) const { int nMapMode; if ( (nMapMode = ::GetMapMode(hdc)) < MM_ISOTROPIC && nMapMode != MM_TEXT) { // when using a constrained map mode, map against physical inch ::SetMapMode(hdc,MM_HIMETRIC); POINT pt; pt.x = sz>cx; pt.y = sz>cy; ::LPtoDP(hdc,&pt,1); sz>cx = pt.x; sz>cy = pt.y; ::SetMapMode(hdc, nMapMode); } else { // map against logical inch for nonconstrained mapping modes int cxPerInch, cyPerInch; cxPerInch = ::GetDeviceCaps(hdc,LOGPIXELSX); cyPerInch = ::GetDeviceCaps(hdc,LOGPIXELSY); sz>cx = MulDiv(sz>cx, cxPerInch, HIMETRIC_INCH); sz>cy = MulDiv(sz>cy, cyPerInch, HIMETRIC_INCH); } POINT pt; pt.x = sz>cx; pt.y = sz>cy; ::DPtoLP(hdc,&pt,1); sz>cx = pt.x; sz>cy = pt.y; }
PictureActiveX.h CUT HERE class CPictureActiveX { ... CPicture picture; // read the picture void Read(UINT nResID); // that's where CPictureActiveX draws the picture HRESULT OnDraw(ATL_DRAWINFO& di); }; PictureActiveX.cpp CUT HERE #include//You may derive a class from CComModule and use it if you want to override //something, but do not change the name of _Module extern CComModule _Module; #include #include // the two following lines of code may be pasted and used somewhere else instead CComModule _Module; _Module.Init(ObjectMap, hInstance, &LIBID_VUMETERLib); // read the picture void CPictureActiveX::Read(UINT nResID) { picture.Load(_Module.GetResourceInstance(),nResID); } // that's where CPictureActiveX draws the picture HRESULT CPictureActiveX::OnDraw(ATL_DRAWINFO& di) { HDC hdc = di.hdcDraw; RECT& rc = *(RECT*)di.prcBounds; picture.Render(hdc, &rc); ... return S_OK; }
Picture.h CUT HERE //////////////////////////////////////////////////////////////// // MSDN Magazine  October 2001 // If this code works, it was written by Paul DiLascia. // If not, I don't know who wrote it. // Compiles with Visual C++ 6.0 for Windows 98 and probably Windows 2000 too. // Set tabsize = 3 in your editor. // #pragma once #include////////////////// // Picture objectencapsulates IPicture // class CPicture { public: CPicture(); ~CPicture(); // Load frm various sosurces BOOL Load(UINT nIDRes); BOOL Load(LPCTSTR pszPathName); BOOL Load(CFile& file); BOOL Load(CArchive& ar); BOOL Load(IStream* pstm); // render to device context BOOL Render(CDC* pDC, CRect rc=CRect(0,0,0,0), LPCRECT prcMFBounds=NULL) const; CSize GetImageSize(CDC* pDC=NULL) const; operator IPicture*() { return m_spIPicture; } void GetHIMETRICSize(OLE_XSIZE_HIMETRIC& cx, OLE_YSIZE_HIMETRIC& cy) const { cx = cy = 0; const_cast (this)>m_hr = m_spIPicture>get_Width(&cx); ASSERT(SUCCEEDED(m_hr)); const_cast (this)>m_hr = m_spIPicture>get_Height(&cy); ASSERT(SUCCEEDED(m_hr)); } void Free() { if (m_spIPicture) { m_spIPicture.Release(); } } protected: CComQIPtr m_spIPicture; // ATL smart pointer to IPicture HRESULT m_hr; // last error code }; Picture.cpp CUT HERE #include "stdafx.h" #include "Picture.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif //////////////////////////////////////////////////////////////// // CPicture implementation // CPicture::CPicture() { } CPicture::~CPicture() { } ////////////////// // Load from resource. Looks for "IMAGE" type. // BOOL CPicture::Load(UINT nIDRes) { // find resource in resource file HINSTANCE hInst = AfxGetResourceHandle(); HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nIDRes), "IMAGE"); // type if (!hRsrc) return FALSE; // load resource into memory DWORD len = SizeofResource(hInst, hRsrc); BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc); if (!lpRsrc) return FALSE; // create memory file and load it CMemFile file(lpRsrc, len); BOOL bRet = Load(file); FreeResource(hRsrc); return bRet; } ////////////////// // Load from path name. // BOOL CPicture::Load(LPCTSTR pszPathName) { CFile file; if (!file.Open(pszPathName, CFile::modeReadCFile::shareDenyWrite)) return FALSE; BOOL bRet = Load(file); file.Close(); return bRet; } ////////////////// // Load from CFile // BOOL CPicture::Load(CFile& file) { CArchive ar(&file, CArchive::load  CArchive::bNoFlushOnDelete); return Load(ar); } ////////////////// // Load from archivecreate stream and load from stream. // BOOL CPicture::Load(CArchive& ar) { CArchiveStream arcstream(&ar); return Load((IStream*)&arcstream); } ////////////////// // Load from stream (IStream). This is the one that really does it: call // OleLoadPicture to do the work. // BOOL CPicture::Load(IStream* pstm) { Free(); HRESULT hr = OleLoadPicture(pstm, 0, FALSE, IID_IPicture, (void**)&m_spIPicture); ASSERT(SUCCEEDED(hr) && m_spIPicture); return TRUE; } ////////////////// // Render to device context. Covert to HIMETRIC for IPicture. // BOOL CPicture::Render(CDC* pDC, CRect rc, LPCRECT prcMFBounds) const { ASSERT(pDC); if (rc.IsRectNull()) { CSize sz = GetImageSize(pDC); rc.right = sz.cx; rc.bottom = sz.cy; } long hmWidth,hmHeight; // HIMETRIC units GetHIMETRICSize(hmWidth, hmHeight); m_spIPicture>Render(*pDC, rc.left, rc.top, rc.Width(), rc.Height(), 0, hmHeight, hmWidth, hmHeight, prcMFBounds); return TRUE; } ////////////////// // Get image size in pixels. Converts from HIMETRIC to device coords. // CSize CPicture::GetImageSize(CDC* pDC) const { if (!m_spIPicture) return CSize(0,0); LONG hmWidth, hmHeight; // HIMETRIC units m_spIPicture>get_Width(&hmWidth); m_spIPicture>get_Height(&hmHeight); CSize sz(hmWidth,hmHeight); if (pDC==NULL) { CWindowDC dc(NULL); dc.HIMETRICtoDP(&sz); // convert to pixels } else { pDC>HIMETRICtoDP(&sz); } return sz; }
Once the source code is inserted, it's possible to use the code in a typical doc/view model with this code :
class CDocument { ... CPicture m_pict; // picture loader instance in some class void Load(UINT nResId) { m_pict.Load(nResId); } CPicture* GetPicture() { return &m_pict; } ... }; class CView { ... void OnDraw(CDC* pDC) { CDocument* pDoc = GetDocument(); ASSERT_VALID(pDoc); CPicture* ppic = pDoc>GetPicture(); ASSERT(ppic); if (*ppic) { CRect rc; GetImageRect(rc); ppic>Render(pDC,rc); } } ... };
For those interested in supporting animated GIF sequences as well, there is an outstanding article[^] on codeproject to do just this.
Enjoy!
]]>
Factors 
Eigenvalue 
RMS 
RE (RSD) 
IE 
IND * 1000 
Chisq Calc. 
Chisq Expected 
Al 2p/3 
4727872000 
82.5236 
159.3106 
34.76442 
398.2765 
26032.99 
2600 
Al 2p/8 
65086870 
3.784555 
23.78739 
7.340948 
65.89305 
136.4193 
2451 
Al 2p/13 
393178.7 
5.875731 
20.74929 
7.842494 
64.04102 
133.7949 
2304 
Al 2p/18 
305001.5 
3.48073 
17.85783 
7.793798 
61.79182 
78.0949 
2159 
Al 2p/23 
156694.8 
3.249367 
16.25038 
7.929371 
63.47803 
59.6866 
2016 
Al 2p/28 
98359.06 
2.757161 
15.2192 
8.135007 
67.64091 
51.1035 
1875 
Al 2p/33 
86168.29 
2.48836 
14.18397 
8.189118 
72.36718 
41.82519 
1736 
Al 2p/38 
65267.54 
2.22333 
13.35424 
8.242415 
79.01916 
37.98182 
1599 
Al 2p/43 
53613.14 
2.247765 
12.61316 
8.257255 
87.59142 
42.46731 
1464 
Al 2p/48 
43569.08 
0.1744253 
11.97161 
8.261198 
98.93895 
0.1869893 
1331 
Al 2p/53 
32387.23 
1.710532 
11.52946 
8.344409 
115.2946 
29.01139 
1200 
Al 2p/58 
28174.98 
2.021671 
11.12658 
8.410907 
137.3652 
33.42906 
1071 
Al 2p/63 
24742 
1.261896 
10.75487 
8.461885 
168.0448 
15.17705 
944 
Al 2p/68 
23980.27 
0.40768 
10.29759 
8.407944 
210.1548 
1.649807 
819 
Al 2p/73 
20710.42 
1.113217 
9.867347 
8.33943 
274.093 
10.69842 
696 
Al 2p/78 
18345.12 
1.155456 
9.424948 
8.226769 
376.9979 
15.75993 
575 
Al 2p/83 
16109.71 
0.7358818 
8.960655 
8.062218 
560.0409 
5.605129 
456 
Al 2p/88 
13003.76 
0.7303461 
8.600543 
7.962556 
955.6159 
5.882052 
339 
Al 2p/93 
12307.15 
0.7049177 
7.99876 
7.608339 
1999.69 
6.193881 
224 
Al 2p/98 
9285.948 
0.000443667 
7.554815 
7.372745 
7554.815 
2.12747E06 
111 
Al 2p/103 
7476.855 
1.90305E13 
0 
0 
0 
2.03675E25 
0 
The chisquare indicates that the data matrix can be reproduced to within experimental error using two abstract factors. This is a result that is consistent with the physical nature of the sample. It is also interesting (from a mathematical standpoint) to note that using all the abstract factors to reproduce the data matrix returns a chisquare of zero (allowing for roundoff errors in the computation). This should always be the case and provides an easy check to see that the calculation has been performed correctly.
All the statistics expect the Indicator Function point to two abstract factors being sufficient to span the factor space for the data matrix.
It is worth examining the data set using a subset of the spectra and Target Testing the spectra not used in the PCA. This allows anomalies to be identified such as spikes in the data. Selecting a representative subset of spectra for the PCA then target testing the remainder is particularly useful for large sets of data.
Table 4: Target Test Report for a Subset of Al 2p Data Set.
Target 
AET 
REP 
RET 
SPOIL 
Al 2p/3 
Al 2p/8 
Al 2p/23 
20.93032 
10.38374 
18.17295 
1.750135 
0.39033 
0.04947 
Al 2p/28 
23.83028 
11.05117 
21.11288 
1.910467 
0.41839 
0.017257 
Al 2p/33 
19.83736 
11.47927 
16.17861 
1.409376 
0.42997 
0.065749 
Al 2p/38 
19.8507 
12.01348 
15.80274 
1.315418 
0.44268 
0.10609 
Al 2p/43 
19.9069 
12.46508 
15.52116 
1.245171 
0.4531 
0.133366 
Al 2p/48 
57.16561 
12.70691 
55.73546 
4.386233 
0.45854 
0.14688 
Al 2p/53 
15.37333 
13.18052 
7.912861 
0.600345 
0.46791 
0.174614 
Al 2p/58 
21.39836 
13.30379 
16.76004 
1.259795 
0.46901 
0.184805 
Al 2p/63 
19.92528 
13.5238 
14.63296 
1.082016 
0.47386 
0.195062 
Al 2p/68 
27.73522 
13.78354 
24.06775 
1.746122 
0.48087 
0.203826 
Al 2p/73 
19.10189 
13.88023 
13.12332 
0.945469 
0.48192 
0.210646 
Al 2p/78 
20.9575 
13.98145 
15.61204 
1.116625 
0.48264 
0.218455 
Al 2p/83 
19.03813 
14.15492 
12.7314 
0.899433 
0.48483 
0.229382 
Al 2p/88 
18.38591 
14.11378 
11.78317 
0.83487 
0.48374 
0.228046 
The SPOIL function and AET statistics (Table 4) show that Al 2p/48 differs in some respect from the other spectra in the list tested. The spectrum in question corresponds to the trace displaying the spikes seen in Figure 6. Also, another spectrum that could be looked at is Al 2p/68. The AET value is high compared to the other spectra. Such spectra may highlight interfaces where either new chemical states appear (either directly from features in the data or indirectly through changes in the background due features outside the acquisition region) or energy shifts due to sample charging have altered the characteristics of the data.
The PCA report in Table 3 includes the spectrum labelled Al 2p/48 in the data matrix. The consequence of not removing the spikes is apparent in the 3D factor space shown in Figure 9, where the abstract factor with third largest eigenvalue clearly contains spikes and the projection point number 10 derived from the Al 2p/48 spectrum is obviously a statistical outlier.
Principal Component Analysis is offered on the "processing" window. The options on the property page labelled "PCA" allow spectra to be transformed into abstract factors according to a number of regimes. These include covariance about the origin and correlation about the origin. Each of these preprocessing methods may be applied with and without background subtraction.
Quantification regions must be defined for each spectrum included in the factor analysis. In addition, each spectrum must have the same number of acquisition channels as the others in the set of spectra to be analysed. The first step in the calculation replaces the values in each spectrum by the result of interpolating the data within the defined quantification region for the spectrum. This is designed to allow energy shifts to be removed from the data used in the factor analysis.
The quantification region also provides the type of background to the spectrum. Performing the analysis on background subtracted data attempts to remove artifacts in the spectrum that derive from other peaks within the vicinity of the energy region. Background contributions can be significant in PCA. Additional primary abstract factors are often introduced as a consequence of changes in the background rather than the underlying peaks within the region of interest. The presence of such abstract factors can be viewed as information extracted from the data, although in many circumstances they can lead to incorrect synthetic models if background contributions are misunderstood.
A factor analysis is performed on the set of spectra displayed in the active tile. Although PCA is offered as a processing option, it is the only processing option that acts on a collection of spectra. Any other option from the processing window would only act upon the first VAMAS block in a selection when that selection is displayed in a single tile.
The principal component analysis is performed when the "Apply" button is pressed. Each spectrum displayed in the active tile is replaced by the computed abstract factors. The order of the VAMAS blocks containing the spectra is used as the order for the abstract factors. The factor corresponding to the largest eigenvalue is entered first. Subsequent blocks receive the abstract factors in descending order defined by the size of the corresponding eigenvalues. A report showing the statistics for understanding the dimensionality of the factor space appears in a dialog window.
A button labelled "PCA Report" allows the current PCA report to be redisplayed. Care should be exercised since the values are subject to any additional processing (including PCA) that may subsequently be applied to any of the spectra included in the original analysis.
The PCA property page includes a button to reset the processing operations for every spectrum displayed in the active tile. This allows a PCA calculation to be undone in one stroke. It will also undo any processing previously performed on the data. PCA is aimed at the raw data; the chisquare statistic is referenced to the raw data and has an undefined meaning when the data have been processed prior to performing factor analysis.
Target Factor Analysis in the form of target testing is also available on the PCA property page. Following a PCA, candidates for the physically meaningful components may be assessed individually or collectively. Choose an abstract factor from the PCA and entering this factor into the active tile. Then select the number of primary abstract factors for use in the target test procedure. A text field is offered on the PCA property page for this purpose and is found in the section headed "Target FA". Next, select the target test spectra in the Browser view and press the button labelled "TFA Apply". A report detailing the statistics calculated from the TFA procedure will appear in a dialog window.
The TFA report may be written to file in an ASCII format with TAB separated columns. When pressed, any of the buttons above the columns on the report will display a file dialog window from which the output textfile can be specified. This method for saving a report to file is used by the PCA report (above) and the Linear Regression Report described below.
Once a set of target spectra has been identified, these spectra can be used to reproduce the original set of spectra through a linear regression step. Enter the set of target spectra into the active tile; then select the original spectra in the Browser view. Press the button labelled "Linear Regression". A report shows the RMS differences between each of the original spectra and the predicted spectra calculated from a linear combination of the set of target spectra displayed in the active tile. The loading used to compute the predicted spectra are listed in the report. The report may be written to file using a similar procedure to the TFA report described above.
Viewing the Data in Factor Space
CasaXPS offers an option on the "Geometry" property page on the "Tile Display" dialog window labelled "Factor Space". If selected, the VAMAS blocks displayed in a tile are used to define the axes for a subspace and the original data are plotted, if possible, as a set of coordinates with respect to these axes. The plot represents a projection of the data space onto the subspace defined by a set of two or three abstract factors.
The abstract factors defining the axes are graphed together with a list of the coordinate values for each of the spectra projected onto the subspace spanned by the chosen abstract factors (Figure 9). A 3dimensional plot provides a visual interpretation for the spectra. Patterns formed by the spectra highlight trends within the data set and the relative importance of the abstract factors can be examined. A plot in which the axes are defined by unimportant factors generally appear random, while factors that are significant when describing the data typically produce plots containing recognisable structure.
]]>Principal Component Analysis *
Introduction *
Theory Behind Principal Component Analysis *
Residual Standard Deviation (RSD or Real Error RE) *
Chisquare *
Target Factor Analysis *
Target Testing *
Principal Component Analysis by Example *
Principal Component Analysis and Real Data *
PCA and CasaXPS *
Viewing the Data in Factor Space *
XPS is a technique that provides chemical information about a sample that sets it apart from other analytical tools. However, the key information sought by the analyst is locked into a data envelope and as a consequence the need for powerful algorithms is paramount when reducing the data to chemically meaningful quantities. Two approaches have been employed on XPS data:
Curve synthesis is probably the most widely used method for data analysis practised by XPS researchers. Unfortunately, statistically good curve fits are not always physically meaningful and, in many cases, great care must be exercised when choosing the model to describe the data. Any assistance in understanding the model is therefore of great value and it is with this end that Principal Component Analysis is offered as a supplementary tool.
Factor analysis is a field that is as broad as it is deep. It is a mathematically challenging tool that requires knowledge of matrix algebra coupled with a feel for a statistical approach to data interpretation. A true understanding for the subject can only be obtained by studying the literature and through practical experience. Therefore the material presented here is only an introduction rather than a complete set of works.
Theory Behind Principal Component Analysis
Factor analysis is a multivariate technique for reducing matrices of data to their lowest dimensionality by use of orthogonal factor space. The challenge is to identify the number of significant factors (principal components) and use this information to model the data using techniques such as Target Transformations or curve fitting.
In XPS the data matrix is composed of spectra where each acquisition channel is viewed as a coordinate in an rdimensional space; r is equal to the number of acquisition channels per spectrum. The problem addressed by PCA is that of determining the number of distinct spectroscopic features present in a particular set of c spectra.
The following example tries to illustrate the nature of the problem. Consider a set of three spectra; each spectrum has three acquisition channels:
s1 = ( 4, 3, 6) , s2 = (2, 3, 2) , s3 = (2, 0, 4) 
The data matrix is given by
These three vectors belong to a 3dimensional space, however they do not span 3dimensional space for the following reason. If a linear combination of the vectors s1, s2 and s3 is used to construct a new vector v, then v always lies in a plane (a 2dimensional subspace of 3dimensional space). The fact that v lies in a plane is a consequence of the following relationships between the three spectra.
s3 = s1 – s2, so v = a s1 + b s2 + c s3 = a s1 + b s2 + c (s1 – s2) = (a + c) s1 + (b – c) s2. 
Thus, two principal components exist for the set of three spectra.
The analysis of the data matrix in the above simple example has been performed by observation. Unfortunately real spectra are not so simple and spotting the linear relationships between the columns of the data matrix requires a more sophisticated approach.
PCA, also known as Eigenanalysis, provides a method for identifying the underlying spectra that form the building blocks for the entire set of spectra. The data matrix is transformed into a new set of rdimensional vectors. These new vectors span the same subspace as the original columns of the data matrix, however they are now characterised by a set of eigenvalues and eigenvectors. The eigenvalues provide a measure for the significance of the abstract factors with respect to the original data. Various statistics can be computed from these values that aid in identifying the dimensionality of the subspace spanned by the spectra.
The procedure for calculating the abstract factors has its roots in linear least square theory. In fact the preferred method is to form a Singular Value Decomposition (SVD) for the data matrix.
Where D is the data matrix formed from c spectra, each containing r channels. U is the same dimension as D, while S and V are c by c matrices. S is a diagonal matrix; the diagonal elements are the square root of the eigenvalues of the correlation matrix
The abstract factors are computed from US. The rows of V are the corresponding eigenvectors of Z; the coordinates of the eigenvectors represent the loading for the abstract factors and specify how linear combinations of these factors can be used to reproduce the original data. Including all of the abstract factors with the appropriate loading enables the data to be reproduced to an accuracy only limited by the precision characteristic of the Eigenanalysis procedure.
The essential feature of the SVD procedure is to compute the abstract factors so that the factor corresponding to the largest eigenvalue accounts for a maximum of the variation in the data. Subsequent abstract factors are generated such that 1) as much variance as possible is accounted for by each new factor and 2) the newest axis is mutually orthogonal to the set of axes already located. The procedure therefore computes an orthogonal basis set for the subspace spanned by the original data matrix that is oriented with respect to the data in a linear least square sense.
In principle, the number of nonzero eigenvalues is equal to the number of linearly independent vectors in the original data matrix. This is true for well posed problems, but even the presence of errors due to numerical operations will result in small eigenvalues that theoretically should be zero. Numerical errors are an insignificant problem compared to the one presented by the inclusion of experimental error in the calculation. Noise in the data changes the underlying vectors so that almost every data matrix of c spectra with r acquisition channels, where c <= r, will span a cdimensional subspace. This is true even though the underlying vectors should only span fewer than c dimensions.
Various statistics are available for identifying the mostly likely dimensionality of a data matrix. These statistics are designed to aid partitioning the abstract factors into primary and secondary factors. The primary factors are those corresponding to the largest n eigenvalues and represent the set of abstract factors that span the true subspace for the data. The secondary factors are those factors that can be associated with the noise and, in principle, can be omitted from subsequent calculations. It is not possible to completely disassociate the true data from the error within the measured data, however the statistics guide the analyst in choosing the most appropriate number of abstract factors that describe the data and therefore the "best guess" dimensionality for the data matrix.
In the case of XPS spectra the experimental error is known to be the square root of the number of counts in an acquisition channel. Under these circumstances where the experimental error is known, a number of statistics have been proposed for determining the size of the true factor space.
Residual Standard Deviation (RSD or Real Error RE)
An alternative name for the RSD (used by Malinowski) is the Real Error (RE).
The RSD is defined to be:
where E_{j }is the j^{th} largest eigenvalue, n is the number of abstract factors used to reproduce the data; c spectra each with r channels are used to construct the data matrix.
RSD_{n} must be compared against the estimated experimental error. If the value computed for RSD_{n} is approximately equal to the estimated error then the first n abstract factors span the factor space. The dimensionality of the original data matrix is therefore n.
Two further statistics may be derived from RSD_{n}, namely, IE_{n} (Imbedded Error) and IND_{n }(Indicator Function) given by:
And
IE_{n} and IND_{n} are statistics that should decrease as the number of primary abstract factors is increased. Once all the primary factors have been included, these statistics should begin to increase since at this point factors from the noise subspace start to interfere with the accuracy of the data description. This minimum is therefore an indicator of the dimensionality of the data subspace.
Bartlett proposed using the chisquare criterion for situations similar to XPS data, where the standard deviation varies from one data channel to the next.
The procedure involves reproducing the data matrix using the abstract factors. Each abstract factor is progressively included in a linear combination in the order defined by the size of the eigenvalues and weighted by the coordinates of the corresponding eigenvectors. The chisquare value for a set of n abstract factors is computed using:
where d_{ij} is an element of the data matrix, d_{ij} is the corresponding approximation to the data point constructed from the first n abstract factors with the largest eigenvalues. The standard deviation for XPS data s_{ij} is the square root of d_{ij}.
The expected value for each n is given by c_{n}^{2} (expected) = (rn)(cn). A comparison between the expected value and the computed value is the basis for determining the number of principal components. Both c_{n}^{2} and its expected value decrease as n increases. c_{n}^{2} initially is larger than c_{n}^{2} (expected) but as n increases a crossover occurs. The true dimensionality of the data matrix is chosen to be the value of n for which c_{n}^{2} is closest to its expected value.
Note that smoothing the data will alter the characteristics of the noise. Performing such preprocessing therefore invalidates the c_{n}^{2} statistic.
Principal Component Analysis provides a set of basis vectors that describe the original set of spectra. Although useful as a means of characterising the data, these abstract factors are in general not physically meaningful. Target Factor Analysis is concerned with identifying vectors that can also describe the data, but with the additional property that they are recognisable as spectra rather than simply abstract vectors in an rdimensional space.
There are numerous methods for transforming the PCA abstract factors to provide vectors that are more open to chemical interpretation. These involve constructing abstract rotation transformations that map the abstract factors into one of the infinite number of alternative basis sets for the factor space. Fortunately there is a technique which when coupled with curve synthesis, lends itself to the analysis of XPS data, namely, Target Testing.
Once a Principal Component Analysis has been performed, the mathematical bridge between abstract and real solutions is Target Testing. Individual spectra can be evaluated to assess whether the corresponding vector lies in the subspace spanned by the chosen primary abstract factors. The essential feature of Target Testing is to form the projection of the target vector onto the subspace spanned by the primary factors, then compute the predicted target vector using this projection. Statistical tests applied to the predicted and test vectors determine whether these two vectors are one and the same. These tests serve as a mean of accepting or rejecting possible fundamental components of the sample.
Ultimately, the goal of target testing is to identify a set of spectra that span the same subspace as the primary abstract factors. Complete models of real factors are tested in the targetcombination step. In the combination step the data matrix is reproduced from the real factors (spectra) rather than from abstract factors and by comparing the results for different sets of real factors, the best TFA solution to a problem can be determined.
Testing a target vector x with respect to the chosen set of primary abstract factors involves forming the projection t onto the subspace spanned by the PCA primary abstract factors. The predicted vector x, calculated using the coordinate values of t to load the corresponding abstract factors, is compared to the original target vector. A target vector that belongs to the subspace spanned by the primary abstract factors should result in a predicted vector that is identical to the initial target vector. Errors in the original data matrix and similar errors in the measured target vector mean that the predicted and target vector differ form each other as well as from the pure target vector x^{*} (x but without error). Estimates for these differences allow a comparison to be made between the predicted and target vector and a decision as to which targets to include in the target combination step.
The apparent error in the test vector (AET) measures the difference between the test and predicted vectors in a root mean square (RMS) sense. Similarly two other RMS quantities estimate the real error in the target vector (RET) and the real error in the predicted vector (REP). These error estimates form the basis for the SPOIL function defined to be approximately equal to the ratio RET/REP.
Principal Component Analysis by Example
The first example illustrating the characteristics of PCA uses a set of artificial data.
Three sets of spectra prepared from synthetic components are used in the PCA. The structure of the artificial data derives from Carbon 1s states within three compounds, namely, PMMA, PVA and PVC (Figure 1.). The proportion of each compound varies throughout each set of ten VAMAS blocks. The data is located in the files c1stest1.vms, c1stest2.vms and c1stest3.vms. The underlying trends introduced into each file are as follows: peaks corresponding to PMMA and PVC obey quadratic adjustments in intensity over the set of ten spectra (PMMA decreases while PVC increases). The difference between the three files is the proportion of PVA in each data envelope. The first file (c1test1.vms) has a constant level of PVA (Figure 2); the second file (c1stest2.vms) varies linearly, first increasing then decreasing; the third file (c1stest3.vms) includes a linear increase in the level of PVA.
The objective is to show how the statistics used in PCA behave for a known problem. Data matrices constructed from the three sets of spectra should have a dimensionality of three.
Figure 1: Artificial C 1s Data 
Note that, although each compound is constructed from a number of C 1s peaks (PMMA 4, PVA 4 and PVC 2), the stoichiometry of these compounds masks the true number of synthetic components actually present in the data. Hence the dimensionality of the data should be three not ten (4+4+2). An additional twist to this example is that two of the underlying envelopes are similar in shape to each other, though not identical (see Figure 1).
The trend throughout the first data set may be seen in Figure 2.
Figure 2: c1s_test1.vms C 1s Spectra 
No noise is present in the data; therefore eigenvalues belonging to the primary set of three abstract factors should be nonzero, while the remaining seven eigenvalues should be zero. The results of applying PCA to these data sets (Table 1) illustrate the uncertainty associated in estimating the dimensionality of the data matrix from the statistics. The fourth largest eigenvalue in each case is small but nonzero. Also the statistics for IE and IND indicate a minimum at eigenvalues other than the expected result. Chisquare is not a valid statistic since no noise is present in the data, however it does show that three abstract factors are sufficient to reproduce the data to within reason.
Table 1: PCA report for file c1stest.vms
FactorC 1s/1 
10861690000 
266.7944 
615.8053 
194.7347 
7602.534 
29055.89 
1800  
C 1s/2 
684568100 
13.0963 
29.86145 
13.35445 
466.5852 
172.5176 
1592  
C 1s/3 
1433862 
0.01064209 
0.02964045 
0.01623474 
0.6049071 
0.000190564 
1386  
C 1s/4 
1.230771 
0.000391784 
0.002107629 
0.001332982 
0.05854525 
9.86356E08 
1182  
C 1s/5 
0.003712633 
0.000385433 
0.001279202 
0.000904532 
0.05116807 
1.20367E07 
980  
C 1s/6 
0.000545838 
0.000230365 
0.001168993 
0.000905498 
0.07306205 
4.86336E08 
780  
C 1s/7 
0.000473059 
0.000240069 
0.001018602 
0.000852223 
0.113178 
5.18512E08 
582  
C 1s/8 
0.000306354 
0.000155331 
0.000891207 
0.000797119 
0.2228016 
2.20338E08 
386  
C 1s/9 
0.000200465 
0.00012725 
0.00076887 
0.000729414 
0.7688698 
1.91008E08 
192  
C 1s/10 
0.000118823 
4.68061E13 
0 
0 
0 
6.13259E23 
0 
It is interesting to see how the eigenvalues change with respect to the three data sets (Figure 3 and Figure 4). The same spectra varied in different ways results in slightly different orientations for the principal component axes and hence different eigenvalues.
The PCA statistics IE and IND have implied a dimensionality other than three (Table 1). The clue to the correct dimensionality of the data lies in the relative size of the eigenvalues. The fourth eigenvalue is in two cases better than five orders of magnitude smaller than the third eigenvalue. This statement has been made with the benefit of a good understanding of what is present in the data. In real situations such statements are themselves suspect and so require support from other data reduction techniques. For example curve fitting using three sets of synthetic peaks all linked with the appropriate stoichiometric relationships would lend support to the hypothesis. Curve fitting such structures is not an exact science and such fits themselves should be supported by statistics gathered from the fitting parameters.
Figure 3: Abstract Factors and Eigenvalues. 
Figure 4. Eigenvalues for c1s_test2.vms Abstract Factors 
The second example illustrates the effects of experimental error on a PCA calculation.
Table 2: PCA Applied to Artificial Data with Simulated Noise.
Factor 
Eigenvalue 
RMS 
RE (RSD) 
IE 
IND * 1000 
Chisq Calc. 
Chisq Expected 
C 1s/1 
10883620000 
267.626 
617.9728 
195.4202 
7629.294 
50489.63 
1800 
C 1s/2 
687172800 
18.93302 
47.75373 
21.35612 
746.152 
3572.687 
1592 
C 1s/3 
2714766 
6.90718 
26.01386 
14.24838 
530.8951 
483.7729 
1386 
C 1s/4 
946794.7 
0.1649431 
2.106561 
1.332306 
58.51557 
0.5688374 
1182 
C 1s/5 
5095.574 
0.0622169 
0.5048702 
0.3569971 
20.19481 
1.247441 
980 
C 1s/6 
226.9936 
0.01656361 
0.1904914 
0.147554 
11.90571 
0.002773735 
780 
C 1s/7 
29.13143 
0.002688086 
0.00847462 
0.007090376 
0.9416245 
5.0833E05 
582 
C 1s/8 
0.03943089 
0.000339289 
0.003105158 
0.002777337 
0.7762894 
3.05649E07 
386 
C 1s/9 
0.003409306 
0.000206314 
0.001523904 
0.001445703 
1.523904 
9.22657E08 
192 
C 1s/10 
0.000466779 
1.26006E12 
0 
0 
0 
7.4912E22 
0 
Real data includes noise. The effect of noise on a PCA calculation can be see from Figure 5 together with the report in Table 2. The data in the file c1stest1.vms has been used together with a pseudorandom number generator to simulate noise that would typically be found in XPS data. The consequence of including a random element in the data is that the eigenvalues increase in size and lead to further uncertainty with regard to which eigenvalues belong to the set of primary abstract factors. Note that the abstract factors in Figure 5 are plotted in the reverse order to the ones in Figure 3 and Figure 4.
Figure 5: c1stest1.vms data plus artificial noise. 
Fortunately, the chisquare statistic becomes more meaningful when noise is introduced into the problem. A comparison between the computed chisquare and its expected values do seem to point to a 3dimensional subspace. The crossover between the two quantities suggests the need for three abstract factors when approximating the data matrix using the results of PCA.
Principal Component Analysis and Real Data
XPS depth profiles generate sets of spectra that are idea for examination via PCA. The spectra are produced by repeatedly performing etch cycles followed by measuring the count rate over an identical energy region. The resulting data set therefore varies in chemical composition with respect to etch time and the common acquisition conditions provide data in a form that is well suited to PCA.
An aluminium foil, when profiled using a Kratos Analytical Axis Ultra, provides a good example of a data set that can be analysed using some of the features on offer in CasaXPS. The data is not chemically or structurally interesting, but does show how trends can be identified and anomalies isolated.
Figure 6 shows a plot of the Al 2p energyregion profiled against etch time. The data envelopes change in shape as the surface oxide layer is removed by the etch cycles to reveal the homogeneous bulk aluminium metal.
It should also be noted from Figure 6 that the data contains an imperfection. One of the energy scans includes data acquired during an instrumental event. Noise spikes are superimposed on the true data and these should be removed before techniques such as curve synthesis are applied. In this case the spikes appear in the background and are therefore obvious to the eye, however similar nonphysical structure that occurs on the side of a peak is less obvious and could be missed.
The first step in performing the Principal Component Analysis is to define a quantification region for each of the spectra to be used in the analysis. These regions specify the acquisition channels that will be used in the data matrix. Also any shifts in the data due to charging can be removed from the calculation by using an offset in the energy region for those spectra affected.
Next, select the set of spectra in the Browser View and display the data in the active tile. The processing property page labelled "PCA" offers a button labelled "PCA Apply". On pressing this button, those spectra displayed in the active tile are transformed into abstract factors. Figure 7 displays the spectra before the PCA transformation while Figure 8 shows the abstract factors generated from the eigenanalysis.
Note that the abstract factors are truly abstract. The first factor (Figure 8) looks like an Al 2p metal doublet, however this is because the Al 2p metal envelope dominates the data set and therefore a vector having a similar shape accounts for most of the variation in the overall set of spectra. A more even weighting between the underlying lineshapes would produce abstract factors that are less physically meaningful in appearance.

The only real use for the abstract factors is judging their significance with respect to the original data. Abstract vectors that derive from noise look like noise, factors that contribute to the description of the data contain structure. The dividing line between the primary and secondary abstract factors can sometimes be assessed based on the appearance of the abstract factors.
Analysing the Al 2p spectra generates abstract factors and eigenvalues that represent the PCA fingerprint for the data. Table 3 is a report of the Al 2p data set generated by CasaXPS and formatted using a spreadsheet program. Each row of the report is labelled by the VAMAS block name that contains the abstract factor corresponding to the listed eigenvalue.
Archivename: graphics/colorspacefaq PostingFrequency: Weekly Lastmodified: 28/9/94 ########################################################### Color spaces FAQ  David Bourgin Date: 28/9/94 (items 5.2 to 5.10 fully rewritten) Last update: 29/6/94  Table of contents  1  Purpose of this FAQ 2  What is a color? 3  What is an image based on a color lookup table? 4  What is this gamma component? 5  Color space conversions 5.1  RGB, CMY, and CMYK 5.2  HSL, HSV 5.3  CIE XYZ and gray level (monochrome included) pictures 5.4  CIE Luv 5.5  CIE Lab and LCH 5.6  The associated standards: YUV, YIQ, and YCbCr 5.7  SMPTEC RGB 5.8  SMPTE240M YPbPr (HD televisions) 5.9  Xerox Corporation YES 5.10 Kodak Photo CD YCC 6  References 7  Comments and thanks  Contents  1  Purpose of this FAQ I did a (too) long period of research in the video domain (video cards, image file formats, and so on) and I've decided to provide to all people who need some informations about that. I aim to cover a part of the Frequently Asked Questions (FAQ) in the video works, it means to provide some (useful?) informations about the colors, and more especially about color spaces. If you have some informations to ask/add to this document, please read item 7. 2  What is a color? A color is defined from human eye capabilities. If you consider a normal human being, his vision of a color will be the same as for another normal being. Of course, to show any colored information, you need a definition (or a model, to use the right word). There are two kinds of color definitions:  The devicedependent: These definitions are more or less accurate. It means that when you display on such a device one color with the particular definition, you get a rendering but when you display on an other device the same color, you get another rendering (more or less dramatically different).  The deviceindependent: This means that the model is accurate and you must adjust your output device to get the same answer. This model is based on some institute works (curves of colors and associated values). From an absolute point of view, it means from a human visual sensation, a color could be defined by:  Hue: The perception of the nuance. It is the perception of what you see in a rainbow.  Colorfulness: The perception of saturation, vividness, purity of a color. You can go from a sky blue to a deep blue by changing this component.  Luminancy: The perception of an area to exhibit more or less light. It is also called brightness. You can blurry or enhance an image by modifying this component. As you see above, I describe a color with three parameters. All the students in maths are quickly going to say that the easier representation of this stuff is a space, a tridimensional space with the previous presentation. And I totally agree with that. That is why we often call 'color space' a particular model of colors. With a color space, colors can be interpreted with response curves. While in a spectral representation of the wave lengths you have a range from infra red to ultra violet, in a normalized color space, we consider a range from black to white. All the pros use the internationally recognized standard CIE 1931 Standard Calorimetric Observer. This standard defines color curves (color matching functions) based on tristimulus values of human capabilities and conditions of view (enlightments, ...). See item 5.3. The CIE (Comission Internationale de l'Eclairage) defined two very useful references for the chromacity of the white point:  D50 white used as reference for reflective copy  D65 white used as reference for emissive devices  D90 white used as an approximative reference for phosphors of a monitor Dxx means a temperature at about xx00 Kelvins. Example, D65 is given at 6504 K. Those temperatures define the white points of particular systems. A white point of a system is the color at which all three of the tristimuli (RGB, for instance) are equal to each other. Being that a white point is achromatic (=it has no color), we can define some temperatures associated to the white references, in order we get a standard. 3  What is an image based on a color lookup table? All of the pictures don't use the full color space. That's why we often use another scheme to improve the encoding of the picture (especially to get a file which takes less space). To do so, you have two possibilities:  You reduce the bits/sample. It means you use less bits for each component that describe the color. The colors are described as direct colors, it means that all the pixels (or vectors, for vectorial descriptions) are directly stored with the full components. For example, with a RGB (see item 5.1 to know what RGB is) bitmapped image with a width of 5 pixels and a height of 8 pixels, you have: (R11,G11,B11) (R12,G12,B12) (R13,G13,B13) (R14,G14,B14) (R15,G15,B15) (R21,G21,B21) (R22,G22,B22) (R23,G23,B23) (R24,G24,B24) (R25,G25,B25) (R31,G31,B31) (R32,G32,B32) (R33,G33,B33) (R34,G34,B34) (R35,G35,B35) (R41,G41,B41) (R42,G42,B42) (R43,G43,B43) (R44,G44,B44) (R45,G45,B45) (R51,G51,B51) (R52,G52,B52) (R53,G53,B53) (R54,G54,B54) (R55,G55,B55) (R61,G61,B61) (R62,G62,B62) (R63,G63,B63) (R64,G64,B64) (R65,G65,B65) (R71,G71,B71) (R72,G72,B72) (R73,G73,B73) (R74,G74,B74) (R75,G75,B75) (R81,G81,B81) (R82,G82,B82) (R83,G83,B83) (R84,G84,B84) (R85,G85,B85) where Ryx, Gyx, Byx are respectively the Red, Green, and Blue components you need to render a color for the pixel located at (x;y).  You use a palette. In this case, all the colors are stored in a table called a palette and the components of all the colors for each pixel (or the vector data) are removed to be replaced with a number. This number is an index in the palette. It explains why we call the palette, a color lookup table. 4  What is this gamma component? An important notion in image processing comes from physical properties of output devices. We often have to correct the colors of an image to get a better rendering, i.e. to sharpen or blurry the picture. With the monitors, this is really true because input signals  proportional to the voltage  don't output a linear answer curve. So, a normal monitor follows an answer curve with an exponential law and a monitor based on LCDs follows an "S" curve with a vicious hook near black and a slow rolloff near white. The adapted correction functions are called gamma correction. We will keep in mind that most of software propose a displaying correction based on a power law relationship. It is given as: Red = a*(Red'^gamma)+b Green= a*(Green'^gamma)+b Blue = a*(Blue'^gamma)+b where Red', Green', and Blue' are the values of volts in input, i.e the values of each primary component for each pixel in the picture you have, Red, Green, and Blue are the adapted light components for your device, a and b are linear transformations to adapt the law relationship, and gamma is the correction factor. Be care: a, b, and gamma are usually real constant for *all* pixels. Note that the software set up a to 1 and b to 0... For CRTCs gray level drawing pictures, gamma is usually within the range of [1.2;1.8] but for true color pictures, the number is usually within the range of [1.8;2.2]. Normal display devices have an usual 2.35 (+/ 0.1) gamma value. I assume in the previous relationships that Red, Green, and Blue are given within the range of [0;1]. But if they were as well positive as negative, you could have, for *example*: Red' = 0.5 and Red = (abs(Red')^gamma) = (0.5^gamma) In some image file formats or in graphics applications in general, you need sometimes some other kinds of correction. These corrections provide some specific processings rather than true gamma correction curves. This is often the case, for examples, with the printing devices or in animation. In the first case, it is interesting to specify that a color must be reaffected in order you get a better rendering, as we see it later in CMYK item. In the second case, some animations can need an extra component associated to each pixel. This component can be, for example, used as a transparency mask. We *improperly* call this extra component gamma correction. 5  Color space conversions Except an historical point of view, most of you are  I hope  interested in color spaces to make renderings and, if possible, on your favorite computer. Most of computers display in the RGB color space but you may need sometimes the CMYK color space for printing, the YCbCr or CIE Lab to compress with JPEG scheme, and so on. That is why we are going to see, from here, what are all these color spaces and how to convert them from one to another (and primary from one to RGB and viceversa, this was my purpose when I started this FAQ). I provide the color space conversions for programmers. The specialists don't need most of these infos or they can give a glance to all the stuff and read carefully the item 6. Many of the conversions are based on linear functions. The best example is given in item 5.3. These conversions can be seen in matrices. A matrix is in mathematics an array of values. And to go from one to another space color, you just make a matrix inversion. E.g. RGB > CIE XYZrec6011 (C illuminant) provides the following matrix of numbers (see item 5.3):  0.607 0.174 0.200   0.299 0.587 0.114   0.000 0.066 1.116  and CIE XYZrec6011 (C illuminant) > RGB provides the following matrix:  1.910 0.532 0.288   0.985 1.999 0.028   0.058 0.118 0.898  These two matrices are the (approximative) inversion of each other. If you are a beginner in this mathematical stuff, skip the previous explainations, and just use the result... 5.1  RGB, CMY, and CMYK The most popular color spaces are RGB and CMY. These two acronyms stand for RedGreenBlue and CyanMagentaYellow. They're devicedependent. The first is normally used on monitors, the second on printers. RGB are called primary colors because a color is produced by adding the three components, red, green, and blue. CMY is called secondary colors because to describe a color in this color space, you consider the reflecting result. So, you become like a painter who puts some (secondary) colors on a sheet of paper. A *white* light is received on the sheet. You have to keep in mind that white in RGB is all components set up to their maximum values. The white color is reflected on the sheet so that the components of white (primary colors) are subtracted from the components of the 'painting' (secondary colors). Such reflecting colors are called secondary colors, for the previous reasons... RGB > CMY  CMY > RGB Red = 1Cyan (0<=Cyan<=1)  Cyan = 1Red (0<=Red<=1) Green = 1Magenta (0<=Magenta<=1)  Magenta = 1Green (0<=Green<=1) Blue = 1Yellow (0<=Yellow<=1)  Yellow = 1Blue (0<=Blue<=1) On printer devices, a component of black is added to the CMY, and the second color space is then called CMYK (CyanMagentaYellowblacK). This component is actually used because cyan, magenta, and yellow set up to the maximum should produce a black color. (The RGB components of the white are completly substracted from the CMY components.) But the resulting color isn't physically a 'true' black. The most usual definition for the CMYK color space is given below: CMY > CMYK  CMYK > CMY Black=minimum(Cyan,Magenta,Yellow)  Cyan=minimum(1,Cyan*(1Black)+Black) Cyan=(CyanBlack)/(1Black)  Magenta=minimum(1,Magenta*(1Black)+Black) Magenta=(MagentaBlack)/(1Black)  Yellow=minimum(1,Yellow*(1Black)+Black) Yellow=(YellowBlack)/(1Black)  RGB > CMYK  CMYK > RGB Black=minimum(1Red,1Green,1Blue)  Red=1minimum(1,Cyan*(1Black)+Black) Cyan=(1RedBlack)/(1Black)  Green=1minimum(1,Magenta*(1Black)+Black) Magenta=(1GreenBlack)/(1Black)  Blue=1minimum(1,Yellow*(1Black)+Black) Yellow=(1BlueBlack)/(1Black)  Of course, I assume that C, M, Y, K, R, G, and B have a range of [0;1]. 5.2  HSL, HSV The representation of the colors in the RGB space is quite adapted for monitors but from a human being, this is not a useful definition. To provide a user representation in the user interfaces, we preferr the HSL color space. The acronym stand for Hue (see definition of Hue in item 2), Saturation (see definition of Colorfulness in item 2), and Luminosity (see definition of Luminancy in item 2). The HSV model can be represented by a trigonal cone, as: Green /\ / \ ^ /V=1 x \ \ Hue (angle, so that Hue(Red)=0, Hue(Green)=120, and Hue(blue)=240 deg) Blue  Red \  / \ > Saturation (distance from the central axis) \  / \  / \  / \ / V=0 x (Value=0 at the top of the apex and =1 at the base of the cone) The big disadvantage of this model is the conversion. Most of publishings (Microsoft, and Foley's "Computer Graphics: Principles and Practice", included) give unaccurate transforms. Actually, the transforms are really complicate, as given below: Hue = (Alphaarctan((RedLuminosity)*(3^0.5)/(GreenBlue)))/(2*PI) with { Alpha=PI/2 if Green>Blue { Aplha=3*PI/2 if Green]]>CIE XYZccir6011 (C illuminant): X 0.606881 0.173505 0.200336 Red  Y = 0.298912 0.586611 0.114478 * Green Z 0.000000 0.066097 1.116157 Blue  Because I'm a programer, I preferr to round these values up or down (in regard with the new precision) and I get: RGB > CIE XYZccir6011 (C illuminant)  CIE XYZccir6011 (C illuminant) > RGB X = 0.607*Red+0.174*Green+0.200*Blue  Red = 1.910*X0.532*Y0.288*Z Y = 0.299*Red+0.587*Green+0.114*Blue  Green = 0.985*X+1.999*Y0.028*Z Z = 0.000*Red+0.066*Green+1.116*Blue  Blue = 0.058*X0.118*Y+0.898*Z The other common recommendation is the 709. The white point is D65 and have coordinates fixed as (xn;yn)=(0.312713;0.329016). The RGB chromacity coordinates are: Red: xr=0.64 yr=0.33 Green: xg=0.30 yg=0.60 Blue: xb=0.15 yb=0.06 Finally, we have RGB > CIE XYZccir709 (709): X 0.412411 0.357585 0.180454 Red  Y = 0.212649 0.715169 0.072182 * Green Z 0.019332 0.119195 0.950390 Blue  This provides the formula to transform RGB to CIE XYZccir709 and viceversa: RGB > CIE XYZccir709 (D65)  CIE XYZccir709 (D65) > RGB X = 0.412*Red+0.358*Green+0.180*Blue  Red = 3.241*X1.537*Y0.499*Z Y = 0.213*Red+0.715*Green+0.072*Blue  Green = 0.969*X+1.876*Y+0.042*Z Z = 0.019*Red+0.119*Green+0.950*Blue  Blue = 0.056*X0.204*Y+1.057*Z Recently (about one year ago), CCIR and CCITT were both absorbed into their parent body, the International Telecommunications Union (ITU). So you must *not* use CCIR 6011 and CCIR 709 anymore. Furthermore, their names have changed respectively to Rec 6011 and Rec 709 ("Rec" stands for Recommendation). Here is the new ITU recommendation. The white point is D65 and have coordinates fixed as (xn;yn)=(0.312713; 0.329016). The RGB chromacity coordinates are: Red: xr=0.64 yr=0.33 Green: xg=0.29 yg=0.60 Blue: xb=0.15 yb=0.06 Finally, we have RGB > CIE XYZitu (D65): X 0.430574 0.341550 0.178325 Red  Y = 0.222015 0.706655 0.071330 * Green Z 0.020183 0.129553 0.939180 Blue  This provides the formula to transform RGB to CIE XYZitu and viceversa: RGB > CIE XYZitu (D65)  CIE XYZitu (D65) > RGB X = 0.431*Red+0.342*Green+0.178*Blue  Red = 3.063*X1.393*Y0.476*Z Y = 0.222*Red+0.707*Green+0.071*Blue  Green = 0.969*X+1.876*Y+0.042*Z Z = 0.020*Red+0.130*Green+0.939*Blue  Blue = 0.068*X0.229*Y+1.069*Z All the conversions I presented until there in this item are not just for fun ;). They can really be useful. For example, in most of your applications you have true color images in RGB color space. How to render them fastly on your screen or on your favorite printer. This is simple. You can convert your picture instantaneously in gray scale pictures see even in a black and white pictures as a magician. To do so, you just need to convert your RGB values into the Y component. Actually, Y is linked to the luminosity (Y is an achromatic component) and X and Z are linked to the colorfulness (X and Z are two chromatic components). Old softwares used Rec 6011 and produced: Gray scale=Y=(299*Red+587*Green+114*Blue)/1000 With Rec 709, we have: Gray scale=Y=(213*Red+715*Green+72*Blue)/1000 Some others do as if: Gray scale=Green (They don't consider the red and blue components at all) Or Gray scale=(Red+Green+Blue)/3 But now all people *should* use the most accurate, it means ITU standard: Gray scale=Y=(222*Red+707*Green+71*Blue)/1000 (That's very close to Rec 709!) I made some personal tests and have sorted them in regard with the global resulting luminosity of the picture (from my eye point of view!). The following summary gives what I found ordered increasingly: +++ Scheme Luminosity level +++ Gray=Green  1  Gray=ITU (D65)  2  Gray=Rec 709 (D65)  3  Gray=Rec 6011 (C illuminant) 4  Gray=(Red+Green+Blue)/3  5  +++ So softwares with Gray=Rec 709 (D65) produce a more dark picture than with Gray=Green. Even if you theorically lose many details with Gray=Green scheme, in fact, and with the 64gray levels of a VGA card of a PC it is hard to distinguish the losts. 5.4  CIE Luv In 1976, the CIE defined two new color spaces to enable us to get more uniform and accurate models. The first of these two color spaces is the CIE Luv which component are L*, u* and v*. L* component defines the luminancy, and u*, v* define chrominancy. CIE Luv is very used in calculation of small colors or color differences, especially with additive colors. The CIE Luv color space is defined from CIE XYZ. CIE XYZ > CIE Lab { L* = 116*((Y/Yn)^(1/3)) whether Y/Yn>0.008856 { L* = 903.3*Y/Yn whether Y/Yn<=0.008856 u* = 13*(L*)*(u'u'n) v* = 13*(L*)*(v'v'n) where u'=4*X/(X+15*Y*+3*Z) and v'=9*Y/(X+15*Y+3*Z) and u'n and v'n have the same definitions for u' and v' but applied to the white point reference. So, you have: u'n=4*Xn/(Xn+15*Yn*+3*Zn) and v'n=9*Yn/(Xn+15*Yn+3*Zn) See also item 5.3 about Xn, Yn, and Zn. 5.5  CIE Lab and LCH As CIE Luv, CIE Lab is a color space introduced by CIE in 1976. It's a new incorporated color space in TIFF specs. In this color space you use three components: L* is the luminancy, a* and b* are respectively red/blue and yellow/blue chrominancies. This color space is also defined with regard to the CIE XYZ color spaces. CIE XYZ > CIE Lab { L=116*((Y/Yn)^(1/3)) whether Y/Yn>0.008856 { L=903.3*Y/Yn whether Y/Yn<=0.008856 a=500*(f(X/Xn)f(Y/Yn)) b=200*(f(Y/Yn)f(Z/Zn)) where { f(t)=t^(1/3) whether Y/Yn>0.008856 { f(t)=7.787*t+16/116 See also item 5.3 about Xn, Yn, and Zn. The CIE Lab has the same problem as RGB, it is not very useful for user interface. That's why you will preferr the LCH, a color space based on CIE Lab (accurate and useful...). LCH stand for Luminosity (see this term in item 2), Chroma (see Colourfulness in item 2), and Hue (see this term in item 2). CIE Lab > LCH L = L* C = (a*^2+b*^2)^0.5 { H=0 whether a=0 { H=(arctan((b*)/(a*))+k*PI/2)/(2*PI) whether a#0 (add PI/2 to H if H<0) { and { k=0 if a*>=0 and b*>=0 { or k=1 if a*>0 and b*<0 { or k=2 if a*<0 and b*<0 { or k=3 if a*<0 and b*>0 5.6  The associated standards: YUV, YIQ, and YCbCr YUV is used in European TVs and YIQ in North American TVs (NTSC). Y is linked to the component of luminancy, and U,V and I,Q are linked to the components of chrominancy. Y come from the standard CIE 1931 XYZ. YUV uses D65 white point which coordinates are (xn;yn)=(0.312713;0.329016). The RGB chromacity coordinates are: Red: xr=0.64 yr=0.33 Green: xg=0.29 yg=0.60 Blue: xb=0.15 yb=0.06 See item 5.3 to understand why the above values. RGB > YUV  YUV > RGB Y = 0.299*Red+0.587*Green+0.114*Blue  Red = Y+0.000*U+1.140*V U = 0.147*Red0.289*Green+0.436*Blue  Green = Y0.396*U0.581*V V = 0.615*Red0.515*Green0.100*Blue  Blue = Y+2.029*U+0.000*V RGB > YIQ  YUV > RGB Y = 0.299*Red+0.587*Green+0.114*Blue  Red = Y+0.956*I+0.621*Q I = 0.596*Red0.274*Green+0.322*Blue  Green = Y0.272*I0.647*Q Q = 0.212*Red0.523*Green0.311*Blue  Blue = Y1.105*I+1.702*Q YUV > YIQ  YIQ > YUV Y = Y (no changes)  Y = Y (no changes) I = 0.2676*U+0.7361*V  U = 1.1270*I+1.8050*Q Q = 0.3869*U+0.4596*V  V = 0.9489*I+0.6561*Q Note that Y has a range of [0;1] (if red, green, and blue have a range of [0;1]) but U, V, I, and Q can be as well negative as positive. I can't give the range of U, V, I, and Q because it depends on precision from Rec specs To avoid such problems, you'll preferr the YCbCr. This color space is similar to YUV and YIQ without the disadvantages. Y remains the component of luminancy but Cb and Cr become the respective components of blue and red. Futhermore, with YCbCr color space you can choose your luminancy from your favorite recommendation. The most popular are given below: +++++  Recommendation  Coef. for red  Coef. for Green  Coef. for Blue  +++++  Rec 6011  0.299  0.587  0.114   Rec 709  0.2125  0.7154  0.0721   ITU  0.2125  0.7154  0.0721  +++++ RGB > YCbCr Y = Coef. for red*Red+Coef. for green*Green+Coef. for blue*Blue Cb = (BlueY)/(22*Coef. for blue) Cr = (RedY)/(22*Coef. for red) YCbCr > RGB Red = Cr*(22*Coef. for red)+Y Green = (YCoef. for blue*BlueCoef. for red*Red)/Coef. for green Blue = Cb*(22*Coef. for blue)+Y (Note that the Green component must be computed *after* the two other components because Green component use the values of the two others.) Usually, you'll need the following conversions based on Rec 6011 for TIFF and JPEG works: RGB > YCbCr (with Rec 6011 specs)  YCbCr (with Rec 6011 specs) > RGB Y= 0.2989*Red+0.5866*Green+0.1145*Blue  Red= Y+0.0000*Cb+1.4022*Cr Cb=0.1687*Red0.3312*Green+0.5000*Blue  Green=Y0.3456*Cb0.7145*Cr Cr= 0.5000*Red0.4183*Green0.0816*Blue  Blue= Y+1.7710*Cb+0.0000*Cr I assume Y is within the range [0;1], and Cb and Cr are within the range [0.5;0.5]. 5.7  SMPTEC RGB SMPTE is an acronym which stands for Society of Motion Picture and Television Engineers. They give a gamma (=2.2 with NTSC, and =2.8 with PAL) corrected color space with RGB components (about RGB, see item 5.1). The white point is D65. The white point coordinates are (xn;yn)=(0.312713; 0.329016). The RGB chromacity coordinates are: Red: xr=0.630 yr=0.340 Green: xg=0.310 yg=0.595 Blue: xb=0.155 yb=0.070 See item 5.3 to understand why the above values. To get the conversion from SMPTEC RGB to CIE XYZ or from CIE XYZ to SMPTEC RGB, you have two steps: SMPTEC RGB > CIE XYZ (D65)  CIE XYZ (D65) > SMPTEC RGB  Gamma correction   Linear transformations: Red=f1(Red')  Red = 3.5058*X1.7397*Y0.5440*Z Green=f1(Green')  Green=1.0690*X+1.9778*Y+0.0352*Z Blue=f1(Blue')  Blue = 0.0563*X0.1970*Y+1.0501*Z where { f1(t)=t^2.2 whether t>=0.0   Gamma correction { f1(t)(abs(t)^2.2) whether t<0.0  Red'=f2(Red)  Linear transformations:  Green'=f2(Green) X=0.3935*Red+0.3653*Green+0.1916*Blue  Blue'=f2(Blue) Y=0.2124*Red+0.7011*Green+0.0866*Blue  where { f2(t)=t^(1/2.2) whether t>=0.0 Z=0.0187*Red+0.1119*Green+0.9582*Blue  { f2(t)(abs(t)^(1/2.2)) whether t<0.0 5.8  SMPTE240M YPbPr (HD televisions) SMPTE give a gamma (=0.45) corrected color space with RGB components (about RGB, see item 5.1). With this space color, you have three components Y, Pb, and Pr respectively linked to luminancy (see item 2), green, and blue. The white point is D65. The white point coordinates are (xn;yn)=(0.312713; 0.329016). The RGB chromacity coordinates are: Red: xr=0.67 yr=0.33 Green: xg=0.21 yg=0.71 Blue: xb=0.15 yb=0.06 See item 5.3 to understand why the above values. Conversion from SMPTE240M RGB to CIE XYZ (D65) or from CIE XYZ (D65) to SMPTE240M RGB, you have two steps: YPbPr > RGB  RGB > YPbPr  Gamma correction   Linear transformations: Red=f(Red')  Red =1*Y+0.0000*Pb+1.5756*Pr Green=f(Green')  Green=1*Y0.2253*Pb+0.5000*Pr Blue=f(Blue')  Blue =1*Y+1.8270*Pb+0.0000*Pr where { f(t)=t^0.45 whether t>=0.0   Gamma correction { f(t)(abs(t)^0.45) whether t<0.0  Red'=f(Red)  Linear transformations:  Green'=f(Red) Y= 0.2122*Red+0.7013*Green+0.0865*Blue  Blue'=f(Red) Pb=0.1162*Red0.3838*Green+0.5000*Blue  where { f(t)=t^(1/0.45) whether t>=0.0 Pr= 0.5000*Red0.4451*Green0.0549*Blue  { f(t)(abs(t)^(1/0.45)) whether t<0.0 5.9  Xerox Corporation YES YES have three components which are Y (see Luminancy, item 2), E (chrominancy of redgreen axis), and S (chrominancy of yellowblue axis) Conversion from YES to CIE XYZ (D50) or from CIE XYZ (D50) to YES, you have two steps: YES > CIE XYZ (D50)  CIE XYZ (D50) > YES  Gamma correction   Linear transformations: Y=f1(Y')  Y= 0.000*X+1.000*Y+0.000*Z E=f1(E')  E= 1.783*X1.899*Y+0.218*Z S=f1(S')  S=0.374*X0.245*Y+0.734*Z where { f1(t)=t^2.2 whether t>=0.0   Gamma correction { f1(t)(abs(t)^2.2) whether t<0.0  Y'=f2(Y)  Linear transformations:  E'=f2(E) X=0.964*Y+0.528*E0.157*S  S'=f2(S) Y=1.000*Y+0.000*E+0.000*S  where { f2(t)=t^(1/2.2) whether t>=0.0 Z=0.825*Y+0.269*E+1.283*S  { f2(t)(abs(t)^(1/2.2)) whether t<0.0 Conversion from YES to CIE XYZ (D65) or from CIE XYZ (D65) to YES, you have two steps: YES > CIE XYZ (D65)  CIE XYZ (D65) > YES  Gamma correction   Linear transformations: Y=f1(Y')  Y= 0.000*X+1.000*Y+0.000*Z E=f1(E')  E=2.019*X+1.743*Y0.246*Z S=f1(S')  S= 0.423*X+0.227*Y0.831*Z where { f1(t)=t^2.2 whether t>=0.0   Gamma correction { f1(t)(abs(t)^2.2) whether t<0.0  Y'=f2(Y)  Linear transformations:  E'=f2(E) X=0.782*Y0.466*E+0.138*S  S'=f2(S) Y=1.000*Y+0.000*E+0.000*S  where { f2(t)=t^(1/2.2) whether t>=0.0 Z=0.671*Y0.237*E1.133*S  { f2(t)(abs(t)^(1/2.2)) whether t<0.0 Usually, you should use YES <> CIE XYZ (D65) conversions because your screen and the usual pictures have D65 as white point. Of course, sometime you'll need the first conversions. Just take care on your pictures. 5.10 Kodak Photo CD YCC YCC is a color space intented for Kodak Photo CD. It uses Rec 709 as gamma correction but its components are defined with the D65 white point and are Y (see Luminancy, item 2) and C1 and C2 (both are linked to chrominancy). YC1C2>RGB  RGB>YC1C2  Gamma correction:  Y' =1.3584*Y Red =f(red')  C1'=2.2179*(C1156) Green=f(Green')  C2'=1.8215*(C2137) Blue =f(Blue')  Red =Y'+C2' where { f(t)=1.099*abs(t)^0.45+0.999 if t<=0.018  Green=Y'0.194*C1'0.509*C2' { f(t)=4.5*t if 0.018 =0.018   Linear transforms:  Y' = 0.299*Red+0.587*Green+0.114*Blue  C1'=0.299*Red0.587*Green+0.886*Blue  C2'= 0.701*Red0.587*Green0.114*Blue   To fit it into 8bit data:  Y =(255/1.402)*Y'  C1=111.40*C1'+156  C2=135.64*C2'+137  Finally, I assume Red, Green, Blue, Y, C1, and C2 are in the range of [0;255]. Take care that your RGB values are not constrainted to positive values. So, some colors can be outside the Rec 709 display phosphor limit, it means some colors can be outside the trangle I defined in item 5.3. This can be explained because Kodak want to preserve some accurate infos, such as specular highlight information. You can note that the relations to transform YC1C2 to RGB is not exactly the reverse to transform RGB to YC1C2. This can be explained (from Kodak point of view) because the output displays are limited in the range of their capabilities. 6  References (most of them are provided by Adrian Ford) "An inexpensive scheme for calibration of a colour monitor in terms of CIE standard coordinates" W.B. Cowan, Computer Graphics, Vol. 17 No. 3, 1983 "Calibration of a computer controlled color monitor", Brainard, D.H, Color Research & Application, 14, 1, pp 2334 (1989). "Color Monitor Colorimetry", SMPTE Recommended Practice RP 1451987 "Color Temperature for Color Television Studio Monitors", SMPTE Recommended Practice RP 37 "Colour Science in Television and Display Systems" Sproson, W, N, Adam Hilger Ltd, 1983. ISBN 0852744137 (Color measuring from soft displays. Alan Roberts and Richard Salmon talked about it as a reference) "CIE Colorimetry" Official recommendations of the International Commission on Illumination, Publication 15.2 1986 "CRT Colorimetry:Part 1 Theory and Practice, Part 2 Metrology", Berns, R.S., Motta, R.J. and Gorzynski, M.E., Color Research and Appliation, 18, (1993). (Adrian Ford talks about it as a must about color spaces) "Effective Color Displays. Theory and Practice", Travis, D, Academic Press, 1991. ISBN 0126976902 (Color applications in computer graphics) Field, G.G., Color and Its Reproduction, Graphics Arts Technical Foundation, 1988, pp. 3209 (Read this about CMY/CMYK) "Gamma and its disguises: The nonlinear mappings of intensity in perception, CRT's, Film and Video" C. A. Poynton, SMPTE Journal, December 1993 "Measuring Colour" second edition, R. W. G. Hunt, Ellis Horwood 1991, ISBN 013567686x (Calculation of CIE Luv and other CIE standard colors spaces) "On the Gun Independance and Phosphor Consistancy of Color Video Monitors" W.B. Cowan N. Rowell, Color Research and Application, V.11 Supplement 1986 "Precision requirements for digital color reproduction" M Stokes MD Fairchild RS Berns, ACM Transactions on graphics, v11 n4 1992 "The colorimetry of self luminous displays  a bibliography" CIE Publication n.87, Central Bureau of the CIE, Vienna 1990 "The Reproduction of Colour in PhotoGraphy, Printing and Television", R. W. G. Hunt, Fountain Press, Tolworth, England, 1987 7  Comments and thanks Whenever you would like to comment or suggest me some informations about this or about the color space transformations in general, please use email: david.bourgin@ufrima.imag.fr (David Bourgin) Special thanks to the following persons (there are actually many other people to cite) for contributing to valid these data:  Adrian Ford (ajoec1@westminster.ac.uk)  Tom Lane (Tom_Lane@G.GP.CS.CMU.EDU)  Alan Roberts and Richard Salmon (Alan.Roberts@rd.bbc.co.uk, Richard.Salmon@rd.eng.bbc.co.uk)  Grant Sayer (grants@research.canon.oz.au)  Steve Westland (coa23@potter.cc.keele.ac.uk) Note: We are installing some new devices in our net and it could be disturbed for some time. Furthermore, I think there's a lot of chances I'm going for my national service on next month, it means from 4/10/94. (Yes I'm young. :).) It will take 10 months but I'll try to read and answer to my emails. Thanks to not be in a hurry ;). ###########################################################
For those unfamiliar with Linear Feedback Shift Registers, see the Primer following Figure 1. For quick information on any of the LFSR parts (shift register, feedback function, output stream, tap sequences) click on the corresponding part in Figure 1.
For a listing of tap sequences for registers 3 to 24 bits long and for 2, 4, and 6 tap sequences for registers 25 to 32 bits long, click here.
For C source code for an LFSR simulator, click here.
For a discussion of uses of LFSR's in cryptography, see "Applied Cryptography" by Bruce Schneier.
For the math behind LFSR's, see "Shift Register Sequences" by Solomon Golomb.
One of the two main parts of an LFSR is the shift register (the other being the feedback function). A shift register is a device whose identifying function is to shift its contents into adjacent positions within the register or, in the case of the position on the end, out of the register. The position on the other end is left empty unless some new content is shifted into the register.
The contents of a shift register are usually thought of as being binary, that is, ones and zeroes. If a shift register contains the bit pattern 1101, a shift (to the right in this case) would result in the contents being 0110; another shift yields 0011. After two more shifts, things tend to get boring since the shift register will never contain anything other than zeroes.
Two uses for a shift register are 1) convert between parallel and serial data and 2) delay a serial bit stream. The conversion function can go either way  fill the shift register positions all at once (parallel) and then shift them out (serial) or shift the contents into the register bit by bit (serial) and then read the contents after the register is full (parallel). The delay function simply shifts the bits from one end of the shift register to the other, providing a delay equal to the length of the shift register.
Some nomenclature:
Clocking) One of the inputs to a shift register is the clock; a shift occurs in the register when this clock input changes state from one to zero (or from zero to one, depending on the implementation). From this, the term "clocking" has arisen to mean activating a shift of the register. Sometimes the register is said to be "strobed" to cause the shift.
Shift direction) A shift register can shift its contents in either direction depending on how the device is designed. (Some registers have extra inputs that dictate the direction of the shift.) For the purposes of this discussion, the shift direction will always be from left to right.
Output) During a shift, the bit on the far right end of the shift register is moved out of the register. This end bit position is often referred to as the output bit. To confuse matters a bit, the bits that are shifted out of the register are also often referred to as output bits. To really muddy the waters, every bit in the shift register is considered to be output during a serial to parallel conversion. Happily, the context in which the term "output" is used generally clears things up.
Input) After a shift, the bit on the left end of the shift register is left empty unless a new bit (one not contained in the original contents) is put into it. This bit is sometimes referred to as the input bit. As with the output bit, there are several different references to input that are clarified by context.
In an LFSR, the bits contained in selected positions in the shift register are combined in some sort of function and the result is fed back into the register's input bit. By definition, the selected bit values are collected before the register is clocked and the result of the feedback function is inserted into the shift register during the shift, filling the position that is emptied as a result of the shift.
The feedback function in an LFSR has several names: XOR, odd parity, sum modulo 2. Whatever the name, the function is simple: 1) Add the selected bit values, 2) If the sum is odd, the output of the function is one; otherwise the output is zero. Table 1 shows the output for a 3 input XOR function.




































The bit positions selected for use in the feedback function are called "taps". The list of the taps is known as the "tap sequence". By convention, the output bit of an LFSR that is n bits long is the nth bit; the input bit of an LFSR is bit 1.
An LFSR is one of a class of devices known as state machines. The contents of the register, the bits tapped for the feedback function, and the output of the feedback function together describe the state of the LFSR. With each shift, the LFSR moves to a new state. (There is one exception to this  when the contents of the register are all zeroes, the LFSR will never change state.) For any given state, there can be only one succeeding state. The reverse is also true: any given state can have only one preceding state. For the rest of this discussion, only the contents of the register will be used to describe the state of the LFSR.
A state space of an LFSR is the list of all the states the LFSR can be in for a particular tap sequence and a particular starting value. Any tap sequence will yield at least two state spaces for an LFSR. (One of these spaces will be the one that contains only one state  the all zero one.) Tap sequences that yield only two state spaces are referred to as maximal length tap sequences.
The state of an LFSR that is n bits long can be any one of 2^n different values. The largest state space possible for such an LFSR will be 2^n  1 (all possible values minus the zero state). Because each state can have only once succeeding state, an LFSR with a maximal length tap sequence will pass through every nonzero state once and only once before repeating a state.
One corollary to this behavior is the output bit stream. The period of an LFSR is defined as the length of the stream before it repeats. The period, like the state space, is tied to the tap sequence and the starting value. As a matter of fact, the period is equal to the size of the state space. The longest period possible corresponds to the largest possible state space, which is produced by a maximal length tap sequence. (Hence "maximal length")
Table 2 is a listing of the internal states and the output bit stream of a 4bit LFSR with tap sequence [4, 1]. (This is the LFSR shown in Figure 1.)
Register States  





Output Stream 
















































































MAXIMAL LENGTH TAP SEQUENCES
LFSR's can have multiple maximal length tap sequences. A maximal length tap sequence also describes the exponents in what is known as a primitive polynomial mod 2. For example, a tap sequence of 4, 1 describes the primitive polynomial x^4 + x^1 + 1. Finding a primitive polynomial mod 2 of degree n (the largest exponent in the polynomial) will yield a maximal length tap sequence for an LFSR that is n bits long.
There is no quick way to determine if a tap sequence is maximal length. However, there are some ways to tell if one is not maximal length:
1) Maximal length tap sequences always have an even number of taps.
2) The tap values in a maximal length tap sequence are all relatively prime. A tap sequence like 12, 9, 6, 3 will not be maximal length because the tap values are all divisible by 3.
Discovering one maximal length tap sequence leads automatically to another. If a maximal length tap sequence is described by [n, A, B, C], another maximal length tap sequence will be described by [n, nC, nB, nA]. Thus, if [32, 3, 2, 1] is a maximal length tap sequence, [32, 31, 30, 29] will also be a maximal length tap sequence. An interesting behavior of two such tap sequences is that the output bit streams are mirror images in time.
CHARACTERISTICS OF OUTPUT STREAM
By definition, the period of an LFSR is the length of the output stream before it repeats. Besides being nonrepetitive, a period of a maximal length stream has other features that are characteristic of random streams.
1) Sums of ones and zeroes. In one period of a maximal length stream, the sum of all ones will be one greater than the sum of all zeroes. In a random stream, the difference between the two sums will tend to grow progressively smaller in proportion to the length of the stream as the stream gets longer. In an infinite random stream, the sums will be equal.
2) Runs of ones and zeroes. A run is a pattern of equal values in the bit stream. A bit stream like 10110100 has six runs of the following lengths in order: 1, 1, 2, 1, 1, 2. One period of an nbit LFSR with a maximal length tap sequence will have 2^(n1) runs (e.g., a 5 bit device yields 16 runs in one period). 1/2 the runs will be one bit long, 1/4 the runs will be 2 bits long, 1/8 the runs will be 3 bits long, etc., up to a single run of zeroes that is n1 bits long and a single run of ones that is n bits long. A random stream of sufficient length shows similar behavior statistically.
3) Shifted stream. Take the stream of bits in one period of an LFSR with a maximal length tap sequence and circularly shift it any number of bits less than the total length. Do a bitwise XOR with the original stream. The resulting pattern will exhibit the behaviors discussed in items 1 and 2. A random stream also shows this behavior.
One characteristic of the LFSR output not shared with a random stream is that the LFSR stream is deterministic. Given knowledge of the present state of the LFSR, the next state can always be predicted.
]]>数字代表计算机的语言。您的计算机如何使用字母来与程序和其他计算机进行通信？一种方法是把字符集 （字符集：一组共享一些关系的字母、数字和其他字符。例如，标准 ASCII 字符集包括字母、数字、符号和组成 ASCII 代码方案的控制代码。）转换为数字形式。
在 20 世纪 60 年代，标准化的需要带来了美国标准信息交换码 (ASCII) （ASCII：将英语中的字符表示为数字的代码。为每个字符分配一个介于 0 到 127 之间的数字。大多数计算机都使用 ASCII 表示文本和在计算机之间传输数据。）（发音为 askkee）。ASCII 表包含 128 个数字，分配给了相应的字符 （字符：字母、数字、标点或符号。）。ASCII 为计算机提供了一种存储数据和与其他计算机及程序交换数据的方式。
ASCII 表上的数字 0–31 分配给了控制字符，用于控制像打印机等一些外围设备。例如，12 代表换页/新页功能。此命令指示打印机跳到下一页的开头。
ASCII 非打印控制字符表
进制  字符  进制  字符  

0  00  空  16  10  数据链路转意  
1  01  头标开始  17  11  设备控制 1  
2  02  正文开始  18  12  设备控制 2  
3  03  正文结束  19  13  设备控制 3  
4  04  传输结束  20  14  设备控制 4  
5  05  查询  21  15  反确认  
6  06  确认  22  16  同步空闲  
7  07  震铃  23  17  传输块结束  
8  08  backspace  24  18  取消  
9  09  水平制表符  25  19  媒体结束  
10  0A  换行/新行  26  1A  替换  
11  0B  竖直制表符  27  1B  转意  
12  0C  换页/新页  28  1C  文件分隔符  
13  0D  回车  29  1D  组分隔符  
14  0E  移出  30  1E  记录分隔符  
15  0F  移入  31  1F  单元分隔符 
数字 32–126 分配给了能在键盘上找到的字符，当您查看或打印文档时就会出现。数字 127 代表 DELETE 命令。
ASCII 打印字符表
进制  字符  进制  字符  进制  字符  

32  20  space  64  40  @  96  60  `  
33  21  !  65  A  97  a  
34  22  "  66  B  98  b  
35  23  #  67  C  99  c  
36  24  $  68  D  100  d  
37  25  %  69  E  101  e  
38  26  &  70  F  102  f  
39  27  '  71  G  103  g  
40  28  (  72  H  104  h  
41  29  )  73  I  105  i  
42  2A  *  74  J  106  j  
43  2B  +  75  K  107  k  
44  2C  ,  76  L  108  l  
45  2D    77  M  109  m  
46  2E  .  78  4F  N  110  n  
47  2F  /  79  5F  O  111  6F  o  
48  30  0  80  50  P  112  70  p  
49  1  81  51  Q  113  q  
50  2  82  52  R  114  r  
51  3  83  53  S  115  s  
52  4  84  54  T  116  t  
53  5  85  55  U  117  u  
54  6  86  56  V  118  v  
55  7  87  57  w  119  w  
56  8  88  58  X  120  x  
57  9  89  59  Y  121  y  
58  :  90  5A  Z  122  z  
59  ;  91  5B  [  123  {  
60  <  92  5C  \  124    
61  =  93  5D  ]  125  }  
62  >  94  5E  ^  126  ~  
63  3F  ?  95  5F  _  127  70  DEL 