65.9K
CodeProject 正在变化。 阅读更多。
Home

Web Ink/Drawing Control

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.70/5 (16投票s)

2006年6月28日

CPOL

15分钟阅读

viewsIcon

331407

downloadIcon

4178

一篇关于使用Microsoft Tablet PC SDK 1.7版本创建和使用与Web浏览器(仅限IE)兼容的Ink或绘图控件的文章。文章提供了一个示例预构建控件供使用和演示。

Sample Image - webinkctrl.gif

引言

本文讨论了如何使用Microsoft Tablet PC SDK 1.7版本创建和使用与Web浏览器(仅限IE)兼容的Ink或绘图控件。文章提供了一个示例预构建控件供使用和演示。此外,如果您对本文有任何疑问,请阅读文末的免责声明。

背景

在亲眼见识了Microsoft的Tablet PC Ink功能后,我曾遗憾地认为他们没有为其Ink库提供Web或ASP.NET支持。直到最近——随着Tablet PC SDK 1.7版本的发布,Microsoft提供了一种创建Ink用户控件的方法,该控件可以嵌入到网页中,并通过Web脚本等方式与Web服务器进行交互。

网上有几篇文章(以及SDK中的一个示例)介绍了这项新功能以及如何构建这样的控件。然而,我认为文档/文章在某些方面存在不足,例如部署此类应用程序的方式表达得令人困惑。此外,除了SDK中的示例之外,没有提供完整的源代码供评估。文章中只显示了零星的代码片段。

因此,本文将跳过控件的创建部分(您可以参考下面的参考网站获取该信息),而是专注于

  1. 使用示例演示控件项目进行部署,以及
  2. 此控件的潜在(创意?)用途以及优缺点。

示例控件还预置了常用的绘图和Ink功能,因此您可以直接使用它,从而节省了从头编写的时间。您也可以通过添加额外的属性和方法或修改现有方法来扩展该控件。

参考网站

主要参考

其他参考资料

Ink Control Overview

本文将从用户控件创建完成之后开始。首先,需要提及一些简要要点

  1. 该控件是一个.NET Windows Form控件(而不是ASP.NET Web控件),您可以将其嵌入到网页中,使其在客户端像Java Applet一样运行。通过JavaScript和Web表单向服务器回发,可以实现与服务器的交互。您也可以选择在Windows Form应用程序中使用该控件。通过利用.NET的WebRequest和WebResponse类或网络类等,还可以扩展该控件以提供与服务器通信的方法。
  2. 该控件可以通过以下两种方式实现与外部环境的交互:(1)将交互代码作为组件/控件放在控件内部;或(2)将交互代码作为控件的public方法,这些方法可以从外部环境调用。在使控件可用于Web方面,第二种方式提供了更好的定制性和可扩展性,以及更好的控件缩放。因此,示例控件项目采用了第二种方式。

使用控件

要求

在浏览器客户端运行或执行该控件需要满足以下条件:

  • .NET Framework 1.1运行时(或SDK)或更高版本
  • Internet Explorer (IE) 5.5或更高版本
  • 浏览器中启用了JavaScript(用于交互功能)
  • Microsoft Ink Library 1.7* 或安装了SP2的Windows XP Tablet PC
  • 鼠标或其他指向设备。建议使用Windows XP Tablet PC系统

* 您可以通过安装一个自定义Microsoft Ink 1.7版本库安装程序或安装Microsoft Tablet PC SDK 1.7来获取Microsoft Ink 1.7版本库。安装了Service Pack 2的Windows XP Tablet PC也默认包含该库。遗憾的是,将控件部署到Web上无法像在Windows Form应用程序中那样(无需安装)将Ink库放置在与应用程序相同的目录中,从而随控件一起加载引用库。要开发和修改控件,您需要使用SDK(即使您已安装了Windows XP Tablet PC w/ SP2)。

嵌入和加载控件

要将控件嵌入和加载到浏览器中,只需在网页中插入一段利用HTML object标签的特殊代码。该标签应类似于以下格式(在我这里奏效了,而其他文章中的一些示例则不行)。

<object id="NameForObject" height="aValue" width="aValue" 
classid="ControlDLLName.dll#ControlNamespaceName.ControlClassName"></object>
<!--// Example here assumes that the DLL is in the same directory as the 
webpage. If not, you will have to modify the path in the classid attribute.
//-->

通过这段代码,当浏览器加载网页时,该对象就会运行。此时您无法做太多事情,因此可以进入下一步。

客户端与控件交互

要为控件和用户提供功能,您可以调用控件内置的方法。但这需要编写JavaScript包装函数来调用控件的方法,如下例所示。

function SetPenColor(pColor){
//common colors only, unrecognized colors results in no change or black ink
//good idea to access control object by having it be a part of a form
//then access object's methods through the form
document.forms[0].NameForObject.SetPenColor(pColor);
}

以下代码列表显示了演示控件中可用的方法。由于安全限制,并非所有方法都可供Web使用,除非您将网站添加为Internet Explorer中的完全受信任站点。
注意:并非所有方法都经过了充分测试,有些可能不如您期望的那样工作。

/* Get & Set Methods */
// Get or set whether anti-alias is used. Default is true
public bool AntiAlias
// Get or set whether to smooth out the drawn ink or not.
public bool FitToCurve
// Get or set whether the pen recognizer detects pressure from the pen
// to adjust the width, height, and intensity of the ink drawn, etc. 
// Default is false.
public bool IgnorePressure
// Set the pen color using common (.NET) color names.
public void SetPenColor(string usrColor)
// Set the background color using common (.NET) color names.
public void SetBackgroundColor(string usrColor)
// Get or set the pen tip style. 0 for ball point, 1 for rectangle.
public int PenTipStyle
// Get or set the pen width in pixels.
public float PenWidth
// Get or set the pen height in pixels.
public float PenHeight
// Get or set transparency level of ink drawn. Values range 
// from 0 to 255. 0 is opague, 255 is transparent.
public int Transparency
/* Editing Mode Methods */
// For set modes, returns true on success in changing modes. Else false.
// Set the control to inking or drawing mode.
private bool SetToInkMode()
// Set the control to ink/object selection mode.
private bool SetToSelectMode()
// Set the control to erasing mode.
private bool SetToDeleteMode()
// Clears the ink in the control.
public void ClearInk()
// For clipboard functions, returns true on success, else false
// Copy ink to clipboard as serialized ink. Not usable when used on the web.
public bool CopyAsSerialInk()
// Copy ink to clipboard as a bitmap. Not usable when used on the web.
public bool CopyAsBitmap()
// Cut ink from control to clipboard as serialized ink. Not usable when used 
// on web.
public bool CutAsSerialInk()
// Cut ink from control to clipboard as a bitmap. Not usable when used on web.
public bool CutAsBitmap()
// Paste ink in clipboard to control. Not usable when used on the web.
public bool Paste()
/* Transformation Methods */
// Create a shear effect on the selected ink based on a set of coordinates
// x = Horizontal shear factor
// y = Vertical shear factor
public void Shear(float x, float y)
// Scale selected ink based on a set of coordinates
// x = Horizontal scale factor
// y = Vertical scale factor
public void ScaleInk(float x, float y)
// Rotate the selected ink for some degrees based on a set of coordinates
// degrees = Number of degrees to rotate
// x = Horizontal coordinate
// y = Vertical coordinate
public void Rotate(float degrees, int x, int y)
// Move the selected ink by an offset coordinate
// x = Horizontal offset
// y = Vertical offset
public void MoveInk(float x, float y)
/* Text Recognition Methods */
// Perform text recognition on ink and return best guess. Only works with 
// Windows XP 
// Tablet PC systems.
public string InkToTextBestGuess()
// Perform text recognition on ink and return the set of best guesses as a 
// newline delimited string. Only works with Windows XP Tablet PC systems.
public string InkToTextResults()
/* I/O Methods */
// Get ink in the control as Base 64 encoded string of the ink in GIF format.
public string ReturnInkAsBase64Gif()
// Get ink in the control as a GIF (byte array)
public byte[] ReturnInkAsGif()
// Get ink in the control as Base 64 encoded string of the serialized ink.
public string ReturnInkAsBase64SerializedInk()
// Get ink in the control as serialized ink
public byte[] ReturnInkAsSerializedInk()
// Load a byte array of ink into the control. Returns true on success.
// inkData = the byte array of ink data.
public bool LoadInk(byte[] inkData)
// Load a base 64 encoded string (of a byte array) of ink/GIF into the 
// control. Returns true on success.
// b64InkData = the base 64 encoded string (of byte data).
public bool LoadInkFromBase64(string b64InkData)
// Load background image to ink control. NOTE: This is meant for windows 
// forms applications only, or requires
// no security restrictions on client side file access in a web application.
// filePath = the file path of background image to load.
public bool LoadBackgroundImage(string filePath)
// Dispose of the control when not needed, like on a webpage unload
//you can use the control's native dispose method, something like:
protected void Dispose()

服务器端与控件交互

要与Web服务器通信,您可以向服务器发出请求,并将Ink数据一起发送。并且您可能能够从服务器回复中检索信息返回到控件(这部分尚未测试或实现)。一个简单的方法是将控件对象作为表单的一部分,并使用JavaScript将Ink数据(存储在隐藏的表单字段中)提交到服务器。要通过Web传递数据,需要将其编码为Base 64字符串,因为HTML不处理二进制数据。然后,您可以在服务器端解码和处理数据。除非您需要使用Microsoft Ink的原生格式,否则通常会将Ink数据作为GIF字节数组传递,因为GIF是一种标准图像格式,易于处理,并且仍然可以加载回Ink控件。以下代码片段展示了如何将控件的Ink数据作为GIF字节数组发送到服务器。

首先,实现检索控件数据并将其存储在隐藏表单字段中的技术。

<!--// This can be done with HTML and a javascript onclick event, for example.
//-->
<input type="button" value="Save as GIF" name="SaveCmd" onclick="SaveAsGif()">
<input type=hidden name="SavedInkData" value="empty">

然后,实现将数据作为Base 64编码字符串发送到服务器的技术。演示项目包含一个简单的服务器处理示例,该示例仅解码并将GIF图像输出到浏览器。在实际应用中,您可以进一步处理图像,存储到数据库,写入文件,或通过电子邮件发送。

function SaveAsGif(){
//store control's ink data in base 64 encoding to hidden form field
document.forms[0].SavedInkData.value = 
               document.forms[0].InkBoxCtrl.ReturnInkAsBase64Gif();
//send the data using a form submit, generally via HTTP POST method
document.forms[0].submit();
}

关于部署演示应用程序和源代码文件的说明

演示应用程序以最简单的方式创建,并非标准的Visual Studio .NET Web应用程序。要部署演示,您只需将其复制到Web服务器即可。无需特殊的Visual Studio .NET或IIS虚拟目录设置。服务器端脚本有ASP.NET或PHP版本,这意味着您可以将此应用程序部署到支持ASP.NET(或PHP)的IIS或任何支持PHP的Web服务器上。只有浏览器客户端需要支持.NET Framework。

对于您可能需要的任何ASP.NET配置文件和设置,可以使用您现有的配置文件,或手动创建,或使用Visual Studio .NET生成。

源代码是Visual Studio .NET 2003 C#控件项目。

注意:该控件在本文所述的Web应用程序中运行良好,但在Windows Form/桌面应用程序中使用时可能存在问题。我曾尝试将控件拖放到Windows Forms项目中并进行编译,结果出现了错误(或者可能是我没有正确将控件添加到应用程序中)。因此,如果您计划在此类项目中使用它,可能需要调整控件以使其正常工作。

IIS部署问题

在部署到IIS时,尤其是在Windows 2003 Server上的IIS 6时,您可能会遇到一些问题。以下是一些解决这些问题的技巧。请按指定顺序尝试:

  1. 在IIS中,验证您的应用程序在“虚拟目录”、“主目录”或“目录”设置下具有“仅脚本”执行权限。如果设置为“脚本和可执行文件”,您将无法下载Web Ink控件DLL。如果您必须使用“脚本和可执行文件”是因为您在使用CGI,您可能需要重新考虑如何部署此应用程序。此方法解决了我的IIS问题。点击此处获取更多信息。
  2. 验证您没有在IIS上使用URLSCAN(来自Microsoft)或类似工具。如果您使用此类工具,则必须将其配置为允许下载DLL文件。点击此处了解如何使用URLScan on IIS。
  3. 如果需要,尝试降低您的IIS服务器安全设置。这可能不是个好主意,而且我认为您实际上不需要这样做。
  4. 当一切都失败时,并且您非常喜欢使用此控件,并且您不需要使用IIS/ASP/ASP.NET,请考虑将应用程序托管在非IIS Web服务器(如Apache)上。

Apache部署问题

Alessandro Torrisi指出了Apache上一个潜在的问题(无论是在Windows还是Linux上运行服务器,为安全起见),即Ink控件DLL未加载到应用程序中。根据Alessandro的说法,要解决此问题,只需在“/etc/apache2/mime.types”文件中添加“application/x-msdownload dll”并重启Apache即可。

关注点

优缺点总结

我认为这样的控件在某些应用程序中具有潜力。缺点是该控件只能在Microsoft客户端环境中运行,需要下载和安装Microsoft Ink库,并且文本识别仅适用于Tablet PC。这些方面可能会阻止人们使用和部署该控件。然而,该控件也有一些积极的方面,特别是其可能的用途以及使用任何服务器端平台(不一定是Microsoft)的选项。总而言之,虽然该控件可能不适用于普通公众和企业用途,但在某些专用应用程序中可能会很有用。而且,它也是业余时间可以玩弄的有趣东西。

可能的(创意?)用例

  • 在Web上书写或绘图,作为使用Java Applet或Macromedia Shockwave/Flash实现的替代方案。Shockwave版本的一个好例子可以在Tutor.com的Live Homework Help信息网站上看到。我曾经是Tutor.com的辅导员,他们确实有一个非常巧妙的Web白板界面。
  • 为运行在Mono开源.NET平台(以及Microsoft .NET)上的ASP.NET应用程序或Web服务提供Ink和绘图支持(通过客户端的控件)。
  • 为非Microsoft和旧版Web服务器平台提供绘图功能
    • Java, J2EE, EJB, servlets, JSP
    • PHP(演示项目提供示例),Perl, Python, Ruby
    • Classic ASP, ColdFusion
    • 仅限标准HTML/DHTML网页,Microsoft HTA应用程序
    • 与Macromedia Shockwave/Flash插件或Java Applet交互/集成以获得更多功能?
  • 使用Web浏览器客户端的控件,以及将Tablet PC作为Web或应用程序服务器,提供Ink识别处理(如果客户端也运行在Tablet PC上就更好了)。
  • 将控件用作可Ink的表单字段
    • 控件的每个实例替换表单中的一个文本框,提交时,服务器处理Ink数据以及其他表单数据。
    • 或者像Tablet PC输入面板一样使用该控件,单击后,Ink被转换为文本,然后可以复制并粘贴到相应的字段中。
      注意:此选项仅在Tablet PC系统上可用。
  • 通过Web支持数字签名(以GIF图像或MS Ink格式)。尽管这可能涉及一些法律、安全和隐私问题。
  • 实现非实时数字白板进行会议——在板上绘图后,用户将数据提交给服务器进行中间存储。然后,应用程序可以周期性/自动地,或由接收用户手动执行,用户可以从服务器加载共享板(或提交用户板)的更新快照。这只是我的想法,并未经过测试。如果可能的话,实现起来可能会很棘手。但如果可能,这是一件很棒的事情。
  • 使用此控件和AJAX来创建精美的动态Web应用程序?
  • 使用控件进行定制Ink应用程序
  • 扩展控件以返回位图、JPEG和其他格式的Ink
  • 最后,您还能提供其他想法吗?

更新的功能和信息 - 截至2007年10月27日

  • 向Ink控件添加了新方法,以从Base 64编码数据加载Ink,并加载背景图像(主要仅适用于Windows Forms应用程序)。
  • 添加了用于Ink功能备份和恢复的客户端代码。备份功能仅备份当前Ink,并覆盖之前的备份。备份使用与保存Ink到服务器相同的隐藏表单字段SavedInkData,因此当您“保存”或将Ink发送到服务器时,当前备份也会被覆盖。您可以进行修改,使备份使用不同的表单字段等。恢复只是从当前备份加载Ink。
    注意:您可能需要点击“恢复”两次才能加载备份,原因不明,至少在我的系统上是这样。
  • 为了调试目的,我添加了一个textbox,其名称与隐藏表单字段“SavedInkData”相同,这样您就可以查看和修改Ink数据的Base 64编码版本。默认情况下,这个新字段是注释掉的。您可以在调试时切换使用此字段而不是隐藏表单字段。
  • 我添加了一个新的Web服务器脚本,该脚本接受提供的图像URL,将其下载(到服务器),转换为Base 64文本,然后返回给浏览器/Web客户端供Web Ink控件使用。不幸的是,这个新脚本目前仅适用于ASP.NET,没有PHP版本。
  • 我添加了一个新的客户端功能,使用XmlHttpRequest将图像的URL传递给服务器,并获取其Base 64编码版本,以便您可以将其加载到Ink控件中。不幸的是,我无法使其在Ink控件中加载。无论如何,这是一个很好的示例,说明如何使用XmlHttpRequest从服务器获取数据加载到您的Ink控件中。我尝试使用Fetch从图像URL获取数据,但您也可以从服务器上的数据库或文件等获取。另外值得注意的是,我使用了我的自定义XmlHttpRequest库来实现这一点(但如果您精通XmlHttpRequest,可以使用原生版本)。有关更多信息,请参阅我的另一篇Code Project文章“Web/HTTP Automation Libraries”。
  • 另请参阅我在本文的评论/论坛帖子,其中包含关于Web Ink、Web Ink识别以及Internet Explorer和Firefox支持的额外更新。

Bug

  • 滚动会导致访问表单元素和选择文本等出现问题。这可能是浏览器或.NET渲染问题。因此,如果您使用大量表单控件,或者控件上方或下方有大量内容,等等,建议将网页以全屏浏览器模式查看,或(仅适用于Tablet PC)以纵向模式查看,以最大程度地减少滚动。否则,请考虑在页面上减少控件或内容。
  • 并非所有实现的控件方法在Web上运行时都得到支持,有些方法可能不如预期那样工作,请注意这一点。
  • 恢复功能可能需要您点击两次才能从备份加载Ink。
  • 从URL加载Ink功能目前无法与Ink控件正常工作。仍保留在演示项目中,作为如何尝试此功能的示例。
  • 自本文首次发布以来,此项目可能无法与最新版本的IE和Windows正确工作。

发布历史

  • 2014年12月7日 - 添加了功能和代码片段,通过数据URI和Ink GIF的base64编码值将GIF图像导出到本地的图像元素。还克隆了网页的一个版本作为Microsoft HTA文件。
  • 2006年6月27日 - 初始发布。未来的增强功能可能包括额外的输出格式和内置的Web请求/响应方法,用于控件与服务器之间的数据输入/输出。
  • 2006年7月4日 - 更新了文章和下载文件,以澄清一些事项。
  • 2006年11月11日 - 更新了文章,增加了关于IIS部署问题的相关信息。
  • 2007年10月27日 - 更新了文章和代码,以解决问题并添加新功能。

免责声明

注意:本文及配套代码并非完全原创。相反,本文旨在在原始文章细节不足之处加以澄清和阐述。此外,还提供了源代码(整合了来自原始文章的代码片段以及我自己的代码和额外功能)和演示应用程序供您自由使用。原始文章只提供了代码片段,没有可以直接使用的完整代码。最后,本文旨在提出和鼓励对这种Ink控件进行标准Microsoft约定/平台之外的创意性使用。

© . All rights reserved.