第九章:GIF输出

GIF格式概述

图形交换格式(GIF,发音为Jiff)由CompuServe公司在1987年引入,它是一种广泛用在Web上,用于带有限的颜色数的锐利边缘的图像,比如说导航图标、logo、曲线图、图表和图标。GIF基于LZW,一种有损压缩的算法,十分适合于简单图形(但是不适合于照片)。

一个GIF图像可以包含多达256种来自24位颜色集的不同的颜色。GIF图像中的像素颜色是一个介于0到255之间的数字,它在包含图像内部的一个颜色调色板上作检索。

任何GIF图像中的像素可以假定为一个“透明色”,或者说是能够看穿透的颜色。这使GIF图像在网页上出现时,可以变成任意的形状。

GIF是唯一的广泛使用的支持动画的图形格式。一个GIF图像可以包含多个,可以逐帧地显示,就像一部小电影。为了减小整个图像大小,有些帧通常小于图像本身,而且以一个偏移量显示,只影响图像中需要重绘的那个部分。

AspJpeg的GIF输出支持

从v2.0版开始,AspJpeg包含了一个新对象,恰好称为Gif,它提供了一个在GIF图像上操作的广阔空间。通过属性Jpeg.Gif来获得这个对象的一个实例。Gif对象是完全自治的,也就是说,它不会被AspJpeg的其它属性和方法影响到。

通过调用Gif.AddFrame方法后面跟着一些其它常规绘图方法,创建一个简单的GIF图像,最后用Save方法保存它。AspJpeg对象中的其它的常规名存方法(SaveUnique方法、SaveBinary方法和属性Binary),Gif对象也支持它们。AddFrame方法需要4个参数:帧宽和帧高,水平偏移和垂直偏移。针对单帧图像,这个今偏移值总是0。

大多数Gif对象的属性和方法只在当前帧上作操作。一旦添加了一个新帧,刚添加的帧成了当前帧。通过把属性Gif.CurrentFrame设置为想要的帧的基于1的索引号,可以把其它帧设置为当前帧。可以利用Gif.FrameCount返回总的帧数。可以利用Gif.RemoveFrame来移除一帧。

Gif对象也支持很多Canvas对象支持常规的绘图方法,比如说PrintText方法、DrawLine方法,等等。设置不同的绘制属性,较之于Canvas对象,多少有点流线性。举个例子,一个Jpeg.Canvas.Pen.Color的等价物是Gif.PenColor。Gif对象中的颜色总是0到255之间的数字,它在当前调色板内部作检索。调色板管理在下面的第九章第五节中所讲解。

以下代码示例创建了一个简单的会动的5帧绘图,带有一些文字和一个饼形图表:

VB Script:

Set Jpeg = Server.CreateObject("Persits.Jpeg")
Set Gif = Jpeg.Gif ' Obtain GIF management object
MarketShare = 6 ' initial market share

' create a 5-frame animated gif

For i = 1 to 5
  Gif.AddFrame 300, 200, 0, 0

  Gif.PenColor = 10
  Gif.BrushColor = 10
  Gif.DrawBar 0, 0, 300, 200

  Gif.PenColor = 201
  Gif.FontFamily = "Courier"
  Gif.PrintText 18, 15, "XYZ, Inc. Market Share"

  Gif.PenColor = 210
  Gif.PrintText 120, 50, 2002 + i

  ' Draw pie chart
  Gif.PenColor = 0
  Gif.BrushColor = 30
  Gif.DrawPie 150, 130, 50, 0, MarketShare * 360 / 100
  Gif.BrushColor = 20
  Gif.DrawPie 150, 130, 50, MarketShare * 360 / 100, 360

  Gif.PrintText 200, 100, MarketShare & "%"

  ' market share almost doubles every year!
  MarketShare = MarketShare * 2 - 3

  ' increase delay on the last frame
  if i = 5 then Gif.Delay = 300 ' 3 sec
Next

' Save
Gif.Save Server.MapPath("chart.gif")

C#:

IASPJpeg objJpeg;
IGif objGif;
objJpeg = new ASPJpeg();
objGif = objJpeg.Gif;
// initial market share of hypothetical XYZ company
int nMarketShare = 6;

// create a 5-frame animated gif
for( int i = 1; i <= 5; i++ )
{
  objGif.AddFrame( 300, 200, 0, 0 );

  objGif.PenColor = 10;
  objGif.BrushColor = 10;
  objGif.DrawBar( 0, 0, 300, 200 );

  objGif.PenColor = 201;
  objGif.FontFamily = "Courier";
  objGif.PrintText( 18, 15, "XYZ, Inc. Market Share", Missing.Value );

  objGif.PrintText( 120, 50, (2002 + i).ToString(), Missing.Value );

  // Draw pie chart
  objGif.PenColor = 0;
  objGif.BrushColor = 30;
  objGif.DrawPie( 150, 130, 50, 0, nMarketShare * 360 / 100 );
  objGif.BrushColor = 20;
  objGif.DrawPie( 150, 130, 50, nMarketShare * 360 / 100, 360 );

  objGif.PenColor = 210;
  objGif.PrintText( 200, 100, nMarketShare.ToString() + "%", Missing.Value );

  // market share almost doubles every year!
  nMarketShare = nMarketShare * 2 - 3;

  // increase delay on the last frame
  if( i == 5 )
    objGif.Delay = 300; // 3 sec
}

// Save
objGif.Save( Server.MapPath("chart.gif") );

点击以下链接以运行该代码示例:

http://localhost/aspjpeg/manual_09/09_animation.asp

http://localhost/aspjpeg/manual_09/09_animation.aspx

GIF图像缩放

Gif对象可以缩放会动的GIF图像,与此同时保留它们的动画和透明度。利用Gif.Resize方法来实现图像的缩放,该方法接受三个可选的参数:新的宽度、新的高度以及缩放算法。你必须要么指定一个新宽度,要么指定一个新高度,或者同时指定两者。如果只指定了一个维度,另一个将根据原来的宽高比自动计算出来。缩放算法的默认值是0(最邻近)。关于AspJpeg支持的缩放算法的更多信息,请阅读用户手册的第四章

原始图像缩放后的图像

上面右边缩小了的图像是用以代码生成的:

VB Script:

...
Gif.Open Server.MapPath("..\images\WalkingCat.gif")
' Resize to half the width, omit height
Gif.Resize Gif.Width / 2

' Save
Gif.Save Server.MapPath("WalkingCat_small.gif")

C#:

...
objGif.Open( Server.MapPath("..\\images\\WalkingCat.gif") );
// Resize to half the width, omit height
objGif.Resize( objGif.Width / 2, Missing.Value, Missing.Value );

// Save
objGif.Save( Server.MapPath("WalkingCat_small.gif") );

点击以下链接以运行该代码示例:

http://localhost/aspjpeg/manual_09/09_resize.asp

http://localhost/aspjpeg/manual_09/09_resize.aspx

注意,一个缩放过的会动的图像的尺寸可能比原始图像还要大,哪怕像素尺寸是变小了(如这个例子中)。还要注意,Resize方法的第三个参数(缩放算法)可以被设置为1,以创建更高品质的缩略图,但是这样的话,有些会动的图像可能会产生不想要的“人为痕迹”。

使用外部图像作为画框

Gif对象可以把RGB图像,比如说JPEG文件转换成256色的GIF文件,并只带有很少的图像品质损失。利用Gif.AddImage方法可以把一个任意的已有的图像添加到一个GIF中,作为一个新帧。这个方法需要AspJpeg对象的一个填塞实例,作为第一个参数,(x,y)让一个画框在被创建的GIF图像内部偏移。在把AspJpeg对象传递给AddImage方法之前,你可以在AspJpeg对象上作任何想要的操作(缩放、裁剪、绘图,等等)。这个被添加的图像必须在RGB颜色空间内。

以下的片段把一个JPEG图像缩小了,把它变成一个单帧的GIF图像:

VB Script:

Set Jpeg = Server.CreateObject("Persits.Jpeg")
Set Gif = Jpeg.Gif
' Another instance of ASPJpeg object
Set Image = Server.CreateObject("Persits.Jpeg")
Image.Open "c:\images\picture.jpg"
Image.PreserveAspectRatio = True
Image.Width = 200

Gif.AddImage Image, 0, 0

' Save
Gif.Save "c:\images\picture.gif"

因为品质的损失和大文件字节大小的减小,把一个JPEG照片转换成GIF并没有什么好处,除非要用别的GIF功能,比如说动画。

第六章第一节的代码示例生成了一个图像,包含了一些照片的缩略图,边靠边地显示。让我们重写这个应用程序以生成一个会动的GIF,轮播显示这些缩略图:

VB Script:

Set Jpeg = Server.CreateObject("Persits.Jpeg")
Set Gif = Jpeg.Gif ' Obtain GIF management object
' Read images from Images directory of the installation
Dim FileNames(3)
FileNames(0) = "apple.jpg"
FileNames(1) = "clock.jpg"
FileNames(2) = "photo.jpg"

Path = Server.MapPath("../images")

' Stipulate output image size
Gif.Width = 100
Gif.Height = 100

For i = 0 To 2

  Jpeg.Open Path & "\" & FileNames(i)

  ' Resize to inscribe in 100x100 square
  Jpeg.PreserveAspectRatio = True
  If Jpeg.OriginalWidth > 100 or Jpeg.OriginalHeight > 100 Then
    If Jpeg.OriginalWidth > Jpeg.OriginalHeight Then
      Jpeg.Width = 100
    Else
      Jpeg.Height = 100
    End If
  End If

  Gif.AddImage Jpeg, (100 - Jpeg.Width) / 2, (100 - Jpeg.Height) / 2
  Gif.DisposalMethod =2
Next

' Save
Gif.Save Server.MapPath("rotation.gif")

C#:

IASPJpeg objJpeg;
IGif objGif;
objJpeg = new ASPJpeg();
objGif = objJpeg.Gif;
// Read images from Images directory of the installation
String [] arrFileNames = new String[3];
arrFileNames[0] = "apple.jpg";
arrFileNames[1] = "clock.jpg";
arrFileNames[2] = "photo.jpg";

String strPath = Server.MapPath("../images");

// Stipulate output image size
objGif.Width = 100;
objGif.Height = 100;

for( int i = 0; i < 3; i++ )
{
  objJpeg.Open( strPath + "\\" + arrFileNames[i] );

  // Resize to inscribe in 100x100 square
  objJpeg.PreserveAspectRatio = 1;
  if(objJpeg.OriginalWidth>100 || objJpeg.OriginalHeight>100)
  {
    if( objJpeg.OriginalWidth > objJpeg.OriginalHeight )
      objJpeg.Width = 100;
    else
      objJpeg.Height = 100;
  }

  objGif.AddImage( (ASPJpeg)objJpeg, 
    (100 - objJpeg.Width) / 2, (100 - objJpeg.Height) / 2 );

  objGif.DisposalMethod = 2;
}

// Save
objGif.Save( Server.MapPath("rotation.gif") );

点击以下链接以运行该代码示例:

http://localhost/aspjpeg/manual_09/09_rotation.asp

http://localhost/aspjpeg/manual_09/09_rotation.aspx

注意整体的GIF图像的尺寸取决于所添加的第一帧的尺寸,除非我们通过属性Gif.Width和属性Gif.Height明确指定它们。在这个应用程序中,我们想让图像被固定在100x100的大小,无论被添加的缩略图的尺寸和方向如何。因此,我们需要明确指定图像的尺寸。

还要注意我们把每一帧的DisposalMethod设置为2,它意味着在绘制后一帧之前,画布必须被重新保存为背景色。这个属性默认是1,表示家一帧需要留在原位,后一帧绘制在前一帧的上面。在我们的应用程序中,这一默认行为不是想要的行为,因为所有的缩略图的尺寸都是不同的。

把真彩色的图像转换成256色的图像,是一个相当复杂的过程,通常被称为“量子化”。转换的速度和品质由属性Gif.Quantization控制。针对这个属性的有效的值是从1到30,1表示最高品质、最慢速度。默认值20为品质和速度提供了一个合理的平衡搭配。

调色板管理

GIF调色板概览

GIF是一个索引化的颜色格式。每个像素的颜色通过一个索引指定,索引指向调色板上的一个RGB条目。每个GIF图像至少包含一个调色板。通常有一个全局调色板,应用到图像的每一帧。但是在某些情况下,一帧有它自己的局部调色板,局部调色板在帧内优先于全局调色板,但是不能应用到别的帧。如果每一帧都有它自己的局部调色板,通常就不存在一个全局调色板了。

GIF格式需要一个调色板,调色板包含了2种、4种、8种、16种、32种、64种、128种甚至256种颜色。调色板内的每个颜色条目精确包含了3字节:R、G、B三个值。

访问并管理调色板

Gif对象提供了一些访问和修改图像的全局调色板和局部调色板的属性和方法。

为了在每一步中指定一个完整的调色板,必须使用SetPalette方法。该方法需要一个布尔值,标志着这个调色板是全局的(True)还是局部的(False),以及一个数字数列,这个数字数列指定了整个调色板的RGB值。这个数列可以包含一个有效的颜色数(2、4、8、依此类推)乘以3。如果第一个参数是False(标示着局部调色板)图像必须已经包含至少一帧,而且调色板所属的当前帧会被影响到。

以下代码片段把全局调色板设置为包含4种颜色:黑(0,0,0)、白(255,255,255)、绿(0,255,0)和黄(255,255,0):

VB Script:

Colors = Array(0,0,0, 255,255,255, 0,255,0, 255,255,0)
Gif.SetPalette True, Colors

C#:

Object [] Colors = new Object[]
  {0,0,0, 255,255,255, 0,255,0, 255,255,0};
objGif.SetPalette( true, Colors );

要想设置或者读取调色板的大小,请使用属性PaletteSize,它和SetPalette方法一样,需要同样的布尔值标记,表录全局/局部调色板。调色板的大小是颜色数,不是颜色成分的总数。有效的值是2、4、8、...256。把这个属性设置为0会产生移除整个调色板的效果。使用这个参数化的属性的示例如下所示:

VB Script:

Gif.PaletteSize( False ) = 256
N = Gif.PaletteSize( False )

C#:

objGif.set_PaletteSize( false, 256 );
int N = objGif.get_PaletteSize( false );

要想设置或取得调色板中的一个独立颜色成分,请使用属性PaletteItem,它需要两个参数:指示全局/局部的布局标记,以及在调色板中想要的颜色成分的地址(基于0检索号)。第一个颜色的三个RGB成分具有地址号0、1、2,第二个颜色,地址号3、4、5,依此类推。地址参数必须在[0,PaletteColor * 3-1]的范围之内。

存档调色板

Gif对象利用SetStockPalette方法让你能够从几个内建的调色板中指定一个。该方法需要两个参数:全局/局部布尔值标记,以及调色板编号。当前,有三个存储的调色板可用:

调色板1:Web安全色(默认调色板,216种真实颜色,40种保留槽);调色板2:标准HTML颜色(16种颜色);调色板3:灰度色(256种颜色)。

调色板1是所有的用Gif对象创建的新图像中的默认的全局调色板。这个调色板包含了在HTML规范中列出的标准Web安全色。总共有216种标准Web安全色,而索引号在216到255之间的颜色没有使用,被设为空白。如果需要的话,这些没有使用的保留槽可以设置为任意的颜色。

标准Web安全色调色板如下所示:

 012345
00000000000330000660000990000CC0000FF
60033000033330033660033990033CC0033FF
120066000066330066660066990066CC0066FF
180099000099330099660099990099CC0099FF
2400CC0000CC3300CC6600CC9900CCCC00CCFF
3000FF0000FF3300FF6600FF9900FFCC00FFFF
363300003300333300663300993300CC3300FF
423333003333333333663333993333CC3333FF
483366003366333366663366993366CC3366FF
543399003399333399663399993399CC3399FF
6033CC0033CC3333CC6633CC9933CCCC33CCFF
6633FF0033FF3333FF6633FF9933FFCC33FFFF
726600006600336600666600996600CC6600FF
786633006633336633666633996633CC6633FF
846666006666336666666666996666CC6666FF
906699006699336699666699996699CC6699FF
9666CC0066CC3366CC6666CC9966CCCC66CCFF
10266FF0066FF3366FF6666FF9966FFCC66FFFF
1089900009900339900669900999900CC9900FF
1149933009933339933669933999933CC9933FF
1209966009966339966669966999966CC9966FF
1269999009999339999669999999999CC9999FF
13299CC0099CC3399CC6699CC9999CCCC99CCFF
13899FF0099FF3399FF6699FF9999FFCC99FFFF
144CC0000CC0033CC0066CC0099CC00CCCC00FF
150CC3300CC3333CC3366CC3399CC33CCCC33FF
156CC6600CC6633CC6666CC6699CC66CCCC66FF
162CC9900CC9933CC9966CC9999CC99CCCC99FF
168CCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF
174CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFF
180FF0000FF0033FF0066FF0099FF00CCFF00FF
186FF3300FF3333FF3366FF3399FF33CCFF33FF
192FF6600FF6633FF6666FF6699FF66CCFF66FF
198FF9900FF9933FF9966FF9999FF99CCFF99FF
204FFCC00FFCC33FFCC66FFCC99FFCCCCFFCCFF
210FFFF00FFFF33FFFF66FFFF99FFFFCCFFFFFF

要想获得给定颜色的索引,把对应到这种颜色最左边的列的数字和最上面的行的数字添加上去。

调色板2包含了标准的16种HTML颜色(以名称的字母表排序),如下所示:

索引颜色名称索引颜色名称
000FFFFaqua8000080navy
1000000black9808000olive
20000FFblue10800080purple
3FF00FFfuchsia11FF0000red
4008000green12C0C0C0silver
5808080grey13008080teal
600FF00lime14FFFFFFwhite
7800000maroon15FFFF00yellow

调色板3包含了来自RGB(0,0,0)到RGB(255,255,255)的256阶灰度色,但是这里不作显示。

透明色

每一帧中的任何一种颜色都可以被假定为透明色,或者是能看透的颜色。这可以利用属性Gif.TranspColor来实现。以下代码片段创建了一个新的GIF图像,并假定颜色索引216(在默认调色板中第一个不使用的索引)设置为透明色,然后给图像填充透明背景:

VB Script:

Gif.AddFrame 100, 100, 0, 0
Gif.TranspColor = 216
Gif.PenColor = 216
Gif.BrushColor = 216
Gif.DrawBar 0, 0, 100, 100
...

C#:

objGif.AddFrame( 100, 100, 0, 0 );
objGif.TranspColor = 216;
objGif.PenColor = 216;
objGif.BrushColor = 216;
objGif.DrawBar( 0, 0, 100, 100 );
...

为了从当前帧是移除透明色,必须把属性Gif.TranspColorSet设置为False

杂项功能

其它帧管理方法

除了上面讲到的Gif.AddFrame方法和Gif.RemoveFrame方法,还有Gif.Clear方法和Gif.MoveFrame方法。

Clear方法,不需要参数,从图像简单移除所有帧。一个没有帧的图像是不能保存或者在上面绘制的。

MoveFrame需要两个参数:原来的索引号和想要的索引号。它把用第一个参数指定的帧移到第二个参数指定的位置。如果当前帧受这个移动的影响,则属性CurrentFrame将反映当前帧的新位置。当前帧依然保持不变,除了位置变了。

其它动画管理属性

属性Gif.Loops控制了动画序列在停止之前需要循环多少次。默认地,该属性是0,表示指定了一个无限的循环次数。

属性Gif.Delay影响当前帧的时间延迟,用百分之一秒来计量。针对每个新加入的帧,这个属性默认被设置为100(1秒钟)。

保存单个帧

在调用Save方法时,如果把属性Gif.FrameToSave设置为一个非零值,会命令该Gif对象只保存用该属性指定的帧,不保存别的帧。这使你能够查看一个会动的GIF中的每个单独的帧。此功能主要用于调试目的。

找到一个最切近的颜色

Gif.FindColosestColor使你能够搜索一个调色板以找到最切近于给定RGB三联体的颜色索引。这个方法需要一个全局/局部布尔值标记以及三个RGB值。它返回一个调色板中的索引,对应于最切近于指定RGB值的颜色。

处理方法

属性Gif.DisposalMethod控制了一个会动的GIF图像中帧如何互相替代。有效的值包括:

  1. 在原地留下当前帧的图像,然后在它的上面绘制下一帧的图像。这是默认方法。
  2. 在呈现下一帧之前,画布局被重存储为背景色。
  3. 在绘制当前帧之前,画布必须被重存储为它前一个状态。

如果你喜欢这篇文章,敬请给站长打赏↑

除特别注明外,本站所有文章均为本站站长原译,转载请注明出处。