第六章:画中画

图像绘制

AspJpeg 1.3以来的版本允许你利用DrawImage方法,把一个图像放到另一个图像的上面。要想使用这个方法,你必须创建两个AspJpeg对象的实例,通过调用Open方法或者OpenBinary方法,把两个图像都填塞进去。在调用Canvas.DrawImage方法的时候,AspJpeg的第二个实例作为参数传递给这个方法,还要加上x和y偏移(以像素计):

Set Jpeg1 = Server.CreateObject("Persits.Jpeg")
Set Jpeg2 = Server.CreateObject("Persits.Jpeg")
Jpeg1.Open Path1
Jpeg2.Open Path2
...
Jpeg1.Canvas.DrawImage 10, 10, Jpeg2 ' optional arguments omitted

以下代码示例为一个在线相册创建了一个“前端页面”,它包含了相册标题(中间对齐)以及三个图像的缩略图,三个图像从文件夹中读出。

要想创建一个空白图像,使用New方法,它接受图像的维度和背景色作为参数。为了把一个文本文件字符串向右对齐,使用了Canvas.GetTextExtent方法。

VB Script:

<%
' Directory with images
Path = Server.MapPath("../images")
' Album Title
Title = "My Favorite Photographs"

Set Jpeg = Server.CreateObject("Persits.Jpeg")

' Create a "blank" image
Jpeg.New 380, 150, &HFFFFFF

' Draw 1-pixel blue frame
Jpeg.Canvas.Pen.Color = &H000080 ' Blue
Jpeg.Canvas.Brush.Solid = False ' to avoid solid bar
Jpeg.Canvas.DrawBar 1, 1, Jpeg.Width, Jpeg.Height

' Set font options
Jpeg.Canvas.Font.Color = &H000000 ' black
Jpeg.Canvas.Font.Family = "Helvetica"
Jpeg.Canvas.Font.Bold = True
Jpeg.Canvas.Font.Size = 15
Jpeg.Canvas.Font.Quality = 4 ' antialiased
Jpeg.Canvas.Font.BkMode = "Opaque"

' Draw album title centered
TitleWidth = Jpeg.Canvas.GetTextExtent( Title )
Jpeg.Canvas.Print (Jpeg.Width - TitleWidth) / 2, 13, Title

' Read images from Images directory of the installation
Dim FileNames(3)
FileNames(0) = "apple.jpg"
FileNames(1) = "clock.jpg"
FileNames(2) = "photo.jpg"
Count = 0
While Count < 3
  ' Draw this image on front page
  Set Img = Server.CreateObject("Persits.Jpeg")
  Img.Open Path & "\" & FileNames(Count)

  ' Resize to inscribe in 100x100 square
  Img.PreserveAspectRatio = True
  If Img.OriginalWidth > 100 or Img.OriginalHeight > 100 Then
    If Img.OriginalWidth > Img.OriginalHeight Then
      Img.Width = 100
    Else
      Img.Height = 100
    End If
  End If
  X = 20 + 120 * Count
  Y = 40

  ' Draw frame for each thumbnail
  Jpeg.Canvas.DrawBar X - 1, Y - 1, X + 101, Y + 101

  ' center image inside frame vert or horiz as needed
  Jpeg.Canvas.DrawImage X + (100 - Img.Width)/2, Y + (100 - Img.Height)/2, Img

  Count = Count + 1
Wend

Jpeg.Save Server.MapPath("frontpage.jpg")
%>

C#:

<%@ Import Namespace="System.Web" %>
<%@ Import Namespace="System.Reflection" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="ASPJPEGLib" %>
<script runat="server" LANGUAGE="C#">

void Page_Load(Object Source, EventArgs E)
{
// Source directory with images
String strPath = Server.MapPath("../images");

// Album Title
String strTitle = "My Favorite Photographs";

IASPJpeg objJpeg;
objJpeg = new ASPJpeg();

// Create a "blank" image for the front page, white background
objJpeg.New( 380, 150, 0xFFFFFF );

// Draw 1-pixel blue frame
objJpeg.Canvas.Pen.Color = 0x000080; // Blue
objJpeg.Canvas.Brush.Solid = 0; // or a solid bar would be drawn
objJpeg.Canvas.DrawBar( 1, 1, objJpeg.Width, objJpeg.Height );

// Set font options
objJpeg.Canvas.Font.Color = 0x000000; // black
objJpeg.Canvas.Font.Family = "Helvetica";
objJpeg.Canvas.Font.Bold = 1;
objJpeg.Canvas.Font.Size = 15;
objJpeg.Canvas.Font.Quality = 4; // antialiased
objJpeg.Canvas.Font.BkMode = "Opaque"; // for antialiasing

// Draw album title centered
int TitleWidth = objJpeg.Canvas.GetTextExtent( strTitle, Missing.Value );
objJpeg.Canvas.Print( (objJpeg.Width - TitleWidth) / 2, 13, 
  strTitle, Missing.Value );

// Enumerate images in the source directory
String[] files = Directory.GetFiles( strPath, "*.*");
int nCount = 0;
foreach( String strFile in files ) 
{
  String strExt =Path.GetExtension( strFile ).ToUpper();
  if( strExt != ".JPG" && strExt != ".GIF" && strExt != ".TIF" )
    continue;

  // Draw this image on front page
  IASPJpeg objImg = new ASPJpeg();
  objImg.Open( strFile );

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

  int X = 20 + 120 * nCount;
  int Y = 40;

  // Draw frame for each thumbnail
  objJpeg.Canvas.DrawBar( X - 1, Y - 1, X + 101, Y + 101 );

  // Center image inside frame vert or horiz as needed
  objJpeg.Canvas.DrawImage( X + (100 - objImg.Width) / 2, Y + (100 - objImg.Height) / 2,    (ASPJpeg)objImg, Missing.Value, Missing.Value, Missing.Value );

  nCount++;
  if( nCount >= 3 )
    break;
}

objJpeg.Save( Server.MapPath("frontpage.jpg") );

FramedImage.Src = "frontpage.jpg";
}
</script>

注意:从v1.8版开始,重写了代码示例06_frontpage.asp,不再使用Microsoft的FileSystemObject对象,因为这个对象可能导致IIS挂起。

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

http://localhost/aspjpeg/manual_06/06_frontpage.asp

http://localhost/aspjpeg/manual_06/06_frontpage.aspx

不透明和透明度

DrawImage方法还提供了三个可选的参数,以指定不透明和透明度参数。

默认地,被嵌入的图像是完全不透明的。不透明度可以通过第四个可选的参数来改变,这个参数必须是一个界于0到1之间的数字。值0意味着图像显示为完全透明(不可见),1表示完全不透明。

以下代码以50%的不透明度嵌入了一个图像:

Photo.Canvas.DrawImage 50, 20, Logo, 0.5

当某个图像被放到另一个图像上面的时候,可以把这个图像的某些像素变得透明。可以通过DrawImage方法的第五个参数使指定变透明的像素的颜色。以下代码使一个图像显示到另一个图像上面的时候,这个图像中所有的红色像素变透明:

Photo.Canvas.DrawImage 50, 20, Logo, , &HFF0000 ' opacity arg omitted

因为JPEG使用有损压缩,像素颜色通常变得稍微有点失真(虽然人类的眼睛可能看不出来)。举个例子,在JPEG压缩的过程中,一个像素的一个颜色成分或所有的颜色成分可能从255(FF)变成254(FE)。为了适应这种缺点,DrawImage方法提供了另一个参数,第五个参数中指定的颜色的一个容差值。该数字必须在0到255之间,并会影响一个像素所有的三种颜色成份。举个例子,以下代码把&H16D636到&H2AEA4A范围内的所有像素都变成透明:

Photo.Canvas.DrawImage 50, 20, Logo, , &H20E040, 10

GIF 透明度

从v1.6版开始,AspJpeg能够从GIF图像中利用TransparencyColor属性抽出透明颜色信息。这个属性使你能够在缩放一个图像的尺寸或者在用Canvas.DrawImage方法把这个图像放到另一个图像的上面的时候,把一个图像的透明色替换成一个任意颜色(比如说白色)。

如果一个图像没有一个透明色(比如说,如果该GIF图像在创建时没有被分配一个透明色,或者如果这个图像根本就是不GIF格式的),试图用TransparencyColor属性将产生一个错误例外。要想检查这个图像是否有透明色,可以使用属性TransparencyColorExists

(注意:并非所有的启用透明度的GIF图像可以使用DrawImage方法正确呈现。从v1.8版开始,你可以使用DrawPNG方法代替它。)

以下代码片段在一个大图像(Big)上面绘制了一个GIF图像(IMg),并保留了GIF图像的透明度,如果情况需要的话。

Img.Open "c:\path\image.gif"

If Img.TransparencyColorExists Then
   Big.Canvas.DrawImage 10, 10, Img, 1, Img.TransparencyColor
Else
   Big.Canvas.DrawImage 10, 10, Img
End If

以下代码片段把白色分配为一个GIF图像的透明色像素:

Jpeg.Open "c:\path\image.gif"

If Jpeg.TransparencyColorExists Then
   Jpeg.ReplaceColor Jpeg.TransparencyColor, &HFFFFFF
End If

对PNG透明度(alpha通道)的支持在后面章节中讲解。

PNG Alpha 通道

便携式网络图形格式,也称为PNG,允许每个像素有一个额外的数据成分(alpha通道),它代表该像素的透明度。因此,一个RGB图像变成RGBa,其中“a”代表alpha通道。

GIF被设置为一个特定的像素要么是完全透明的,要么是完全不透明的。但是PNG和GIF不同。这使启用了alpha的PNG图像能够与任何背景图像完美地混合(见下面的示例)。

从v1.7开始,AspJpeg支持PNG的alpha通道。这个功能对于需要给一个图像“印戳”一个图标或文本字的应用程序来说特别有用。

原始图标

作为透明GIF绘制图标:糟糕的颜色混合。

作为带alpha通道的PNG图像绘制图标:平滑的颜色混合。

要想在一个大图像上面绘制一个PNG图像,与此同时考虑这个图像的alpha通道,就必须使用Canvas.DrawPNG方法。这种方法的参数是小图像相对于在图像的X和Y偏移,以及PNG文件的路径:

jpeg.Open "c:\path\house123.jpg"
jpeg.Canvas.DrawPNG 10, 10, "c:\path\logo.png"
jpeg.Save "c:\path\out.jpg"

从v1.8开始,DrawPNG方法也能够识别GIF图像了。你必须使用这种方法来绘制带透明色的GIF图像,而不是使用DrawImage置诸高阁法,因为后者可能不能够正确呈现某些启用透明度的GIF图像。

除了DrawPNG方法,还有DrawPNGBinary方法,它与DrawPNG方法一样,除了它的最后一个参数是一个包含了要绘制的图像的字节二进制阵列。这是另一个必须使用的方法,如果PNG或GIF图像从数据库中读取,而不是来自一个磁盘文件。

在v2.7.0.3版中,DrawPNG方法和DrawPNGBinary方法既考虑到背景图像的alpha通道,也考虑到被绘制的图像的alpha通道,从而获得更精确的颜色混合。

演示文档6在线演示了DrawPNG方法。

透视投影

更新:在v2.8版本中,AspJpeg为透视图像提供了更强大的更灵活的方法,使它能够贴合到3D表面,包括平面、球面、圆柱面、圆锥面,等等。在第十一章:3D表面映射中讲解了这个功能。

从v2.5版本以来,AspJpeg允许一个被绘制的图像被拉伸到用四个角点定义的一个任意的四边形区域。这个功能使你在一个图像上面渲染另一个图像的时候,能够创建一个透视效果,就像下面的广告牌的照片所示:

要想对一个图像应用透视投影,上面讲过的DrawImage方法依然可以使用,但是调用这个方法的前提是你必须通过调用MoveTo方法,随后三次调用LineTo方法,定义一个路径,包含了四个精确的点。该路径的四个点定义了一个四边形区域,在主图像内部的这个区域上,在调用DrawImage方法的时候,渲染了小图像。路径的第一个点对应于小图像的左上角。

使用任何图像编辑器,比如说Microsoft Paint或Photoshop,从左上角开始,以顺时针的顺序确定你的主图像内部的四个点的坐标(特指下面图像上的P1、P2、P3和P4),如下所示:

在你的脚本中使用这些坐标,如下所示:

VB Script:

<%
Set Jpeg = Server.CreateObject("Persits.Jpeg")
' Open image to draw on
Jpeg.Open Server.MapPath(".") & "/../images/billboard.jpg"

' Create 2nd instance of AspJpeg to hold image to be drawn
Set Img = Server.CreateObject("Persits.Jpeg")
Img.Open Server.MapPath(".") & "/../images/clock.jpg"

With Jpeg.Canvas
  ' Create path: must contain 4 points, start with upper-left corner
  .MoveTo 127, 465
  .LineTo 686, 68
  .LineTo 810, 504
  .LineTo 56, 731

  ' Draw image. 1nd and 2nd arguments (X and Y) are ignored.
  .DrawImage 0, 0, Img
End With

Jpeg.Save Server.MapPath("perspective.jpg")
%>

C#

IASPJpeg objJpeg = new ASPJpeg();
// Compute path to source image
String strPath = Server.MapPath("../images/billboard.jpg");

// Open source image
objJpeg.Open( strPath );

// Create 2nd instance of AspJpeg to hold image to be drawn
IASPJpeg objImg = new ASPJpeg();
objImg.Open( Server.MapPath("../images/clock.jpg") );

ICanvas objCanvas = objJpeg.Canvas;

// Create path: must contain 4 points, start with upper-left corner
objCanvas.MoveTo( 127, 465 );
objCanvas.LineTo( 686, 68 );
objCanvas.LineTo( 810, 504 );
objCanvas.LineTo( 56, 731 );

// Draw image. 1nd and 2nd arguments (X and Y) are ignored.
objCanvas.DrawImage( 0, 0, (ASPJpeg)objImg, Missing.Value, Missing.Value, Missing.Value );

objJpeg.Save( Server.MapPath("perspective.jpg") );

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

http://localhost/aspjpeg/manual_06/06_perspective.asp

http://localhost/aspjpeg/manual_06/06_perspective.aspx

注意,当以“透视投影模式”使用DrawImage方法的时候,只有第三个和第四个参数(图像和不透明度)是有用的,别的参数都被忽略掉了。

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

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