正所谓“ 工欲善其事,必先利其器” ,环境搭建乃是最重要的一步。以前上大学的时候阅过不少大师写的教材,第一章便是讲什么是Hello World ,但我却在环境搭建上郁闷得要死,于是要在屏幕上显示一条Hello World 是那么的艰难。
介绍
微软的Silverligth2 包含了对由“SeaDargon ”团队创建的Deep Zoom 技术的支持。简单地说,Deep Zoom 技术就是能让你查看很大的一副图片但仅仅将当前显示在你屏幕上的部分发送到你的浏览器里。你也可以对图片进行平滑的缩放和平铺。这就像是在线地图将一副很大的图片划分成很多很小的平铺的图片然后将那些你正在查看的发送到你的屏幕上。这所带来的好处就是你不必花大量时间来下载一副很大的图片数据而这些甚至你从来就没有看或注意到过。这项技术非常酷,但说实话,要为这些图片序列创建正确的坐标信息却不是一件容易的事情,而刚好Expression 团队为我们带来了一个工具,我们暂时称为“Deep Zoom Composer ”
Expression Deep Zone Composer 让我们可以按照任何方式排列一个图片集中的图片(很大的图片哈),然后将他们的最终排列方式发布到Silverlight2 中一个称为MultiScaleImage 的控件中去。我们这个工具的输出是平铺图的一个集合,你最终将看到的是一个XML 文件,一个BIN 文件以及一个编号的文件夹的集合,每个文件夹中包含着最终图片排列的一部分。在一个MultiScaleImage 控件中引用一个BIN 文件所用到的XAML 大致是这个样子:
<MultiScaleImage x:Name=”deepZoomObject” Source=”samle/info.bin”/>
谁会使用这样的应用程序呢?任何对Silverlight2 感兴趣并且想对大图进行缩放平铺等高级操作的人。如果没有这项技术要想完成标准带宽下的连接显得异常困难。这个工具的受众是一些很平常的用户,有个几个很普通的场景会用到,地图是其中之一,另外一个可能是在线广告其用于为产品提供一个非常易于交互的和非常细节的观察角度。
接下来是描述一下用户如何创建一个Deep Zoom Composer app 项目,排列导入的图像,最后输出为一个Deep Zoom Image.
启动
欢迎屏幕
启动Deep Zoom Composer 后用户会看到一个飞溅屏幕(splash screen )紧接着是欢迎屏幕,在欢迎屏幕上我们可以看到两个标签页:Project 和Help.
Project 标签页为用户提供了一个最近查看的项目列表以及New Project 和Open Project 操作。
Help 标签页提供了诸如User Guide 之类的有用信息。
项目
Deep Zoom Composer 项目结构如下:
1 . 工作区
创建一个Deep Zome Image 的工作流是这样的:1. 导入,2. 构图(排列),3. 输出
导入:
在“导入工作区”中,用户可以导入一些图片到项目中
图片栏:
用户点击“Add images ”按钮来导入图片。这些图片将被显示在一个图片栏中。右击图片并选择“Delete from project ”可以将图片从项目中删除。
图片预览:
当用户选择图片栏中的一个图片时在左边可以看到它的预览图。其文件名,尺寸,文件大小等将显示在左下方。
用户可以指定文件夹,但Deep Zoom Composer 仅仅会导入合法的图片文件类型,也就是说其支持PNG ,JPEG ,TIFF 和BMP 这几种格式,其他文件格式将被忽略。注意:目前Deep Zoom Composer 不支持同名文件的导入。
构图(排列)
“Compose ”工作区为用户提供了定位和排列图片的功能 :
图片栏
在“Compose ”工作区中,被导入到项目的图片被显示在图片栏,用户可以拖放这些图片到画板中。图片栏为用户提供了如下几个基础的功能:
“All Image ”标签页,在这里图片栏将显示项目中的所有图片。那些显示成半透明的图片表示其正在被使用(即是被拖到了Compose 工作区中)
“Layer View ”标签页,这个标签页仅仅显示那些被Compostion 使用中的图片。用户可以面板上的箭头按钮来改变图片在画板上的Z 轴顺序。
“Visibility ”在图片旁边的眼睛图标用于设置该图片在画板上的可见性。
画板
用户可以在Compose 工作区的画板中创建和编辑“Compositions ”。该工作区提供了一
个拥有定位和排列图片能力的设计区和一个基础工具集(selection, pan, zoom )以及基础的排列特性(align & distribute )。可以通过拖拽的方式将图片栏的图片添加到画板中,用户可以在画板中排列这些图片并通过导航器来导航以及使用几种工具来修改。当然,用户也可以通过拖拽修饰器(技术图片选中状态下的几个小方块)和下面的一排按钮来修改和布局。
工具:
选择工具,其允许用户选择和操作图片。用户可以通过Adorner (修饰器?那几个小东东真不知道专业名称叫什么,抱歉)来操作图片
Pan 工具,其允许用户通过点击和拖拽来滚动可视区域。
缩放工具,当用户选择缩放工具是,其可以点击可视区域中的任何一个位置来缩放放大该点。当按住ALT 并单击时缩小,或使用ALT+= 快捷键来方法或ALT+- 快捷键来缩小。如果用户点击最后一个缩放图标(普通缩放图标的右边那个),在画板中的当前元素将被缩放以适合屏幕。
布局功能:
其也支持一些布局和分配功能(比如Make same height )
当用户点击“Align/Distribute ”和“Make Same ”图标时将执行下面的这些选择(之一):
左对齐,左右居中对齐,右对齐,上对齐,上下居中,下对齐,横向分布,纵向分布,等宽,等高。
输出
输出工作区中为用户提供了导出为Deep Zoom Image 或集合的功能
输出预览,最终的composition将被显示在导出标签页中。
导出设置,用户可以对导出进行一些设置,比如文件名,位置等。那个复选框提供了让用户设置是否将其导出到一个Deep Zoom Collection中。
今天介绍一下如何建立一个DeepZoom 应用。如果你用过DeepZoomComposer ,你会发现在DeepZoomComposer 中导出的时候“CreateCollection ” 选项。这里决定了你导出的是一张整图还是一个图片集合,关于导出整图,你可以参考 大 V 的 初试 Deep Zoom Composer( Step by Step|More Pictures)(超酷 +必试) 这篇文章,写得很不错( 建议你阅读一下,因为与其重复的内容我将省略了)。关于图片集合下面会讲到。
- <MultiScaleImage
- x:Name="msi"
- ViewportWidth="1.0"
- Source="/XXXX/info.bin" MouseLeftButtonDown="msi_MouseLeftButtonDown" MouseLeftButtonUp="msi_MouseLeftButtonUp" MouseMove="msi_MouseMove"/>
而应该将info.bin 替换成:items.bin ,在导出的文件中你会找到该文件,这表示你导出的是一个集合。
这时运行你的程序你变可以看到一个图片集合显示在那里了,但可惜的是没有任何交互。在那之前我们先了解一下MultiScaleImage 的几个重要属性(我不知道是不是我的Silverlight SDK 版本不对,在MultiScaleImage 中其关键的几个属性、方法与事件没有相关注释,所以有必要将我对这几个属性、方法、事件的理解列举一下)
Source :即DeepZoomComposer 导出的文件(单个文件为Info.Bin, 集合为Items.Bin)
SubImages :子图片,如果DeepZoomComposer 导出的为集合的话,其将集合中每个元素作为一个MultiScaleSubImage 对象存储在这个集合中。对子图片的操作就全靠它了。
UsingSprings :是否启用其默认动画(就是那中很飘逸的感觉,取消则比较生硬了)
Viewport: 视口位置(可以简单理解成眼睛所在位置,有过3D 编程经验的比较容易理解)
ViewportWidth :视口宽度,视口越宽看到的东西越到(感觉上离图片越远,或图片缩小了)
AspectRatio :宽高比。
ElementToLogicPoint() :从元素坐标(物理坐标)转换为逻辑坐标 (元素坐标则是我们平时所说的普通坐标,逻辑坐标则是指元素左上角为0,0 点,右下角为1 ,1 点而言的相对坐标)
LogicToElementPoint() :与上述相反。
ZoomAboutLogicPoint(double, double, double) :按逻辑坐标缩放,第一个参数指定缩放增量,后两个参数指定缩放中心。
MotionFinished 事件:动画结束(或者说当你操作图片或子图后其运动结束)
关于子图:
每个子图是一个MultiScaleSubImage 对象,其在MultiScaleImage 的SubImages 属性中
如何移动子图位置:
你可以通过指定该子图的ViportOrgin 属性来指定它的位置,比如
subImage.ViportOrgin = new Point(x,y);
所以如果你想将子图像WPF 中一样排列成Grid 元素一样,没办法,一个一个计算x ,y 然后指定吧。
如何缩放子图:
你可以通过子图的ViewportWidth 属性来控制,值越大子图就越小。
如何显示或隐藏子图:
没有visibility 或相关属性,但你可以通过设置其Opacity (不透明度)来实现。
如何获取指定子图的位置和大小(Rect )
参考这个方法:
- private Rect GetSubImageRect(MultiScaleImage msi, int index)
- {
- if (index < 0 || index >= msi.SubImages.Count)
- {
- return Rect.Empty;
- }
-
- MultiScaleSubImage image = msi.SubImages[index];
- double scaleBy = 1 / image.ViewportWidth;
-
- return new Rect(-image.ViewportOrigin.X * scaleBy,
- -image.ViewportOrigin.Y * scaleBy,
- scaleBy,
- (1 / image.AspectRatio) * scaleBy);
- }
如何根据X ,Y 坐标得到相应位置处的子图:
参考这个方法:
- private int GetImageIndexFromPosition(MultiScaleImage msi, Point pt)
- {
- pt = msi.ElementToLogicalPoint(pt);
-
- for (int i = 0; i < msi.SubImages.Count; i++)
- {
- MultiScaleSubImage image = msi.SubImages[i];
- double scaleBy = 1 / image.ViewportWidth;
- Rect imageRect = this.GetSubImageRect(msi, i);
- if (imageRect.Contains(pt))
- {
- return i;
- }
- }
-
- return -1;
- }
相信有了这些知识就已经能做出不错的效果了哈:)关于如何分组子图将在本系列的后续随笔中讲解,谢谢!