图像查看器Virtualizer

imageview类支持无限数量的项目通过用户的视图布局(参考图像查看器布局).有了这种支持,查看器可以用来加载具有大量页面和较大物理图像大小的文档。当然,在物理内存中可以保存多少图像是有硬件限制的,而图像查看器提供了Virtualizer机制来支持按需加载/卸载图像数据。

例如,图像查看器正在使用带有连续滚动的垂直布局。用户正在尝试加载一个有1000页的PDF文件,每一页都是典型的8.5乘11英寸的文档大小。假设页面是每像素24位,那么像素大小为2550 * 3300,每一页未压缩数据的物理大小为24MB,总共需要24MB * 1000 = 24GB的物理内存来保存所有这些页面。

在上面的垂直布局中,页面(每个页面包含在一个ImageViewerItem对象)将不会同时在屏幕上全部可见。事实上,当用户滚动或缩小查看器时,它们中的大多数将保持不可见状态,直到它们进入视图。查看器需要关于条目数量和每个条目的物理大小的信息,以便进行布局和滚动条计算。但是图像数据本身是不需要的,除非项目是可见的。一个更好的方法是直到项目即将在视图中可见时才加载图像数据。以及当项目从视图中消失且不可见时丢弃图像数据。的ImageViewerVirtualizer执行的就是这个。它是一个抽象类,允许您根据需要轻松加载和卸载项数据,并完全控制呈现占位符和控制要在内存中缓存的项的数量。

例子

400页测试文档

我们首先需要的是一份有很多页的文件。下面是使用LEADTOOLS创建这样一个文档的代码:

私人静态无效CreateTestDocument ()//创建一个400页的PDF文件每一页长8.5英寸,宽11英寸var宽度= 8.5;var身高= 11.0;var分辨率= 300;varpixelWidth = (int)(宽度*分辨率+ 0.5);varpixelHeight = (int)(高度*分辨率+ 0.5);varpageccount = 400;var文件名=字符串.Format (@“C: \ LEADTOOLS21 \资源\图片\ {0}Pages.pdf”, pageCount);如果(File.Exists(文件名)File.Delete(文件名);使用var编解码器=RasterCodecs ())varpageMode = codecssavepagemode .覆盖;varpageNumber = 1;pageNumber <= pageCount;pageNumber + +)使用varrasterImage = CreatePageImage(pixelWidth, pixelHeight,分辨率,pageNumber))编解码器。保存(rasterImage, fileName, RasterImageFormat。RasPdfLzw, 24, 1,1, -1, pageMode);pageMode = CodecsSavePageMode.Append;私人静态RasterImage CreatePageImage (intpixelWidth,intpixelHeight,int决议,intpageNumber)钢笔[]钢笔=笔。红色,笔。绿色,笔。蓝色,};Brush[]画笔=刷子。红色,刷子。绿色,刷子。蓝色的};钢笔钢笔=钢笔[pageNumber % 3];画笔画笔=画笔[pageNumber % 3];varrasterImage = rasterImage。创建(pixelWidth, pixelHeight, 24,分辨率,RasterColor.FromKnownColor(RasterKnownColor.White));varhdc = RasterImagePainter.CreateLeadDC(rasterImage);使用vargraphics = graphics . frommhdc (hdc))varrc =矩形(0,0,pixelWidth, pixelHeight);图形。DrawRectangle(笔,rc。X, rc。Y, rc。宽度- 2 rc。高度- 2);图形。DrawRectangle(笔,rc。X + 1 rc。Y + 1 rc。宽度- 3 rc。高度- 3);var文本=字符串.Format (“页面{0}”, pageNumber);使用var字体=字体(“天线”, 72, FontStyle.Regular))使用var科幻小说=StringFormat ())科幻小说。对齐= stringalign . center;科幻小说。linealign = stringalign . center;vartextSize =图形。MeasureString(文本、字体);浮动Y = 10;浮动X = 10;(y < pixelHeight)(x < pixelWidth)图形。DrawString(文本,字体,笔刷,x, y);x += textSize。宽度+ 80;y += textSize。身高+ 80;X = 10;RasterImagePainter.DeleteLeadDC (hdc);返回rasterImage;

图像查看器

创建400页的简历PDF文档,创建一个垂直视图布局的图像查看器:

//创建一个垂直布局的新图像查看器实例ImageViewerViewLayoutImageViewerVerticalViewLayout ();ImageViewer =imageview (viewLayout);//设置一些属性imageview。Dock = DockStyle.Fill;imageview。BackColor = Color.Bisque;//添加边框(也需要一些填充)imageview。ImageBorderThickness = 1;imageview。ItemPadding =填充(imageViewer.ImageBorderThickness);//观看时考虑到图像的分辨率,因此图像大小为8.5 * 11英寸//当缩放为1:1时,屏幕将显示8.5 x11英寸imageview。UseDpi =真正的//添加到表单中.Controls.Add (imageview);imageViewer.BringToFront ();//增加平移/缩放交互模式单击并拖动以平移图像,然后按住鼠标单击//和拖动来放大/缩小imageViewer.InteractiveModes.Add (ImageViewerPanZoomInteractiveMode ());

不使用Virtualizer添加页面

让我们尝试在查看器中按原样加载该文档。这段代码将把所有页面作为项添加到文档中:

var文件名=@ " C: \ LEADTOOLS21 \资源\ \ 400 pages.pdf图像”使用var编解码器=RasterCodecs ())codecs.Options.RasterizeDocument.Load.Resolution = 300;//不更新,直到我们有所有的页面imageViewer.BeginUpdate ();//获取页面数intpageCount = codecs.GetTotalPages(文件名);varpageNumber = 1;pageNumber <= pageCount;pageNumber + +)var项=ImageViewerItem ();项。图像=编解码器。负载(文件名,pageNumber);imageViewer.Items.Add(项);imageViewer.EndUpdate ();

试着运行这段代码。在花费大量时间加载所有页面后,它将在64位系统上工作,并且很可能在32位系统上出现内存不足异常而失败。系统不能一次将所有这些映像数据加载到内存中。显然,我们需要一个更好的方法。

只添加大小信息的页面

如在图像查看器项目,图像查看器支持创建没有图像数据的项目。所有的观众需要的是项目的数量以及它们的大小(像素和分辨率)。因此,让我们修改代码,添加没有图像数据的项:

var文件名=@ " C: \ LEADTOOLS21 \资源\ \ 400 pages.pdf图像”使用var编解码器=RasterCodecs ())codecs.Options.RasterizeDocument.Load.Resolution = 300;//不更新,直到我们有所有的页面imageViewer.BeginUpdate ();//获取每页的页数和大小intpageCount;LeadSize图象尺寸;LeadSizeD决议;使用var信息=编解码器。GetInformation(文件名,真正的))//获取页面数pageCount = info.TotalPages;//获取像素大小imageSize = LeadSize.Create宽度,info.Height);//获取分辨率决议= leadsize . create(信息。XResolution info.YResolution);varpageNumber = 1;pageNumber <= pageCount;pageNumber + +)var项=ImageViewerItem ();//设置查看器创建正确布局所需的成员项。ImageSize = ImageSize;项。Resolution = Resolution;//添加imageViewer.Items.Add(项);imageViewer.EndUpdate ();

运行这段代码,并注意到查看器几乎立即启动并运行。添加正确大小的空白页,您可以自由地缩放和平移图像。

的仿真器

最后一步是根据需要填充图像数据。这可以通过创建一个映像虚拟器派生类来轻松完成,该类可以根据需要处理映像数据的加载和释放。

创建一个新类并添加以下代码:

//从抽象ImageViewerVirtualizer派生的类公共MyVirtualizer: ImageViewerVirtualizer公共MyVirtualizer() {}//包含大图的文件私人字符串_fileName;公共MyVirtualizer (字符串文件名):基地()//保存文件_fileName =文件名;//保存在内存中的缓存项的数量,默认为16。改为4.MaximumItems = 4;受保护的覆盖对象LoadItem (ImageViewerItem项)//当项目进入视图时调用此方法//并且不是缓存在内存中//对于这个例子,我们所需要的只是加载图像//从原始文件。但是我们也可以装载其他的//状态和数据从数据库或使用反序列化。//在这个例子中,项目索引是页面索引//但是,我们可以使用item .Tag属性或派生我们的//拥有自己的类来保存加载页面所需的数据//索引是基于0的,所以加1得到页码varpageNumber =.ImageViewer.Items.IndexOf(item) + 1;//加载页面并返回使用var编解码器=RasterCodecs ())codecs.Options.RasterizeDocument.Load.Resolution = 300;返回编解码器。加载(_fileName, 0, CodecsLoadByteOrder.)BgrOrGray, pageNumber, pageNumber);受保护的覆盖无效SaveItem (ImageViewerItem项,对象数据)//当一个项目将要被删除时,这个方法被调用//从缓存。在这个例子中,我们没有任何事情要做//如果你的应用程序需要序列化,你可以修改代码//数据到磁盘或数据库受保护的覆盖无效DeleteItem (ImageViewerItem项,对象数据)//当项目不再使用时调用此方法//在这个例子中,我们简单地处置我们加载的RasterImagevar图片=数据作为RasterImage;如果(图片! =image.Dispose ();受保护的覆盖无效RenderItemPlaceholder (ImageViewerRenderEventArgs e)//该方法在加载项目时被调用,并给我们一个机会//为用户提供提示//让我们渲染一个Loading…项目信息var变换=.ImageViewer.GetItemImageTransform (e.Item);vargraphics = e.PaintEventArgs.Graphics;varpt = LeadPointD。创建(0,0);pt = transform.Transform(pt);图形。拉带(“加载……”.ImageViewer。字体、画笔。黑色(浮动pt。X (浮动) pt.Y);

最后,在查看器中设置我们的虚拟器

//添加我们的虚拟器imageview。仿真器=MyVirtualizer(文件名);

运行这个演示并注意:

Virtualizer和多线程笔记

ImageViewerVirtualizer方法将从一个与主UI线程不同的线程中调用。这对于确保用户可以平滑地平移和缩放而不受干扰是很重要的。DeleteItem当项目被删除或查看器被处理时将被调用(如果AutoDisposeImages设置为真正的),以确保资源得以释放。

RenderItemPlaceholder方法总是在创建查看器的同一线程中调用。

LEADTOOLS成像、医疗和文档
188金宝搏的网址客服|支持|联系我们|知识产权公告
©1991 - 2021领德科技有限公司版权所有。