某些多页文件格式可以缓慢加载使用默认的实现RasterCodecs。特别是文档文件格式如多克斯/医生,XLSX / XLS, RTF、PDF和TXT。
大多数光栅文件格式,比如TIFF,有一个简单的标题的开头的文件显示的页面数量以及每个页面的文件的位置。因此,从一个10页的文件,读取页面5软件首先读取标题,然后马上跳到第5页并解析它。在这种情况下,没有其他的部分文件(和其他页面)是感动。阅读下一页的点球(页码6)没有任何先验信息读取和解析的头又通常是一个快速操作。
一些文档文件格式,比如PDF、初还包含一个头文件的数量和位置指示页面。然而,页面可能有交叉引用文档中其他部分。例如,字体数据几乎总是存储在全球PDF文档在一个特定的位置。因此,阅读从一个10页第5页文件,软件必须先读头,然后读全球字体数据(然后跳转到第5页来解析)。阅读下一页的点球(页码6)没有任何先验信息读取和解析头以及所有全球交叉引用的部分文件,将为每个页面重复。
其他类型的文档格式,如纯文本不包含一个头。每个页面的总数量和位置必须由遍历计算每一行的文本和呈现在一个虚拟的页面,增加页面数虚拟页面运行时的空间。在文件中的每一行都必须这样处理。因此,阅读从一个10页第5页文件,软件将呈现和丢弃一个虚拟页面上页1到4,然后渲染页面5到物理页。从本质上讲,RasterCodecs将创建一个“文件格式头”一个文本文件,其中包括每个页面的数量和位置的物理文件。阅读下一页的点球(页码6)没有任何先验信息再次执行这个操作(这一次渲染和丢弃页1到5)。
解决方案是使用优化加载机制RasterCodecs。与优化加载RasterCodecs可以保持内部状态信息文档而不是出错时需要重新加载它。例如,在上面的PDF文件中,全局字体表保存在内存中,为后续页面重用。文本文件的情况下,创建了虚拟的头,然后使用和更新页面加载。
作为一个例子,考虑sample.pdf115页的PDF文件。下面的示例显示了一个实现加载这个文件使用RasterCodecs:
私人静态无效TestOptimizeLoad (字符串imageFileName,booluseOptimizeLoad)
{
使用(RasterCodecs编解码器=新RasterCodecs ())
{
/ /启动一个计时器
var秒表=新秒表();
/ /使用GetInformation获取文件的总页数;
intpageCount;
双这回= 0;
双totalTime = 0;
/ /看看我们是否需要把优化负载。
如果(useOptimizeLoad)
codecs.StartOptimizedLoad ();
stopwatch.Restart ();
CodecsImageInfo imageInfo = codecs.GetInformation (imageFileName,真正的);
这回= stopwatch.ElapsedMilliseconds;
totalTime + =这回;
pageCount = imageInfo.TotalPages;
imageInfo.Dispose ();
Console.WriteLine ($“GetInformation{这回}女士”);
/ /遍历每个页面和加载它
为(intpageNumber = 1;pageNumber < = pageCount;pageNumber + +)
{
stopwatch.Restart ();
RasterImage图像=编解码器。负载(imageFileName pageNumber);
这回= stopwatch.ElapsedMilliseconds;
totalTime + =这回;
image.Dispose ();
Console.WriteLine ($“加载页面{pageNumber}{这回}女士”);
}
/ /是否需要关闭优化加载回和自由它的数据。
/ /注意这不是真正需要在这个例子
/ / RasterCodecs后立即处理,将照顾
如果(useOptimizeLoad)
codecs.StopOptimizedLoad ();
Console.WriteLine ($”“女士总时间{totalTime});
}
}
代码是非常简单的:首先,它获取文件的总页数,然后它加载每个页面RasterImage对象。它还将记录每个操作时间加起来的总时间。
调用这个方法TestOptimizeLoad(“样本。pdf”,假)
结果在以下测试机:
GetInformation女士花了114
加载页面1 103 ms
加载页面2女士花了61
加载页面3女士花了46
/ /剪断
装载113页了43个女士
装载114页40毫秒
装载115页50微秒
总时间6622毫秒
调用这个方法TestOptimizeLoad(“样本。pdf”,真的)
结果在以下相同的测试机:
GetInformation女士花了114
加载页面1 115 ms
加载页面2 31女士
加载页面3女士花了42
/ /剪断
装载113页了43个女士
装载114页40毫秒
装载115页了48女士
总时间5577毫秒
比较第一与第二个6.6秒在5.6秒。因此,通过调用StartOptimizedLoad操作加快了15%。
另一个文件是sample.txt。这是一个大文本文件348页。这里是结果TestOptimizeLoad(“样本。txt”,假)
:
GetInformation女士花了294
加载页面1 193 ms
加载页面2女士花了155
/ /剪断
装载346页161 ms
装载347页138 ms
装载348页146 ms
总时间51706毫秒
而TestOptimizeLoad(“样本。pdf”,真的)
结果:
GetInformation女士花了259
加载页面1女士花了59
加载页面2 34女士
加载页面3女士花了34
/ /剪断
装载346页34女士
装载347页35女士
装载348页33毫秒
总时间12992毫秒
比较第一与第二个在13秒52秒(几乎400%的加速。)
比较TIFF、PDF和文本加载时间的使用优化加载显示了极端的影响RasterCodecs,如下所示:
TIFF文件不受影响,因为格式包含所有所需的信息快速载入任何页面simple-to-read-and-parse头。
PDF文件是加速,这取决于文件数据(大小和数量之间的交叉引用页)。
文本文件加快是最直接与性能的增加成正比的页面数量的文件。
上面的示例使用优化加载数据转换所有输入文件的页面。为PDF文件,改进速度将明显当大文件(1000页或更多)转换。其他文件格式,速度可以显著改善甚至用更少的页面(只有10页)。
TIFF / BigTIFF文件使用一个简单的机制(IFD,每个页面或文件偏移量)。关于使用IFD的更多信息,请参考大型TIFF / BigTIFF文件加载和保存。
以下文件格式支持:
最简单的方法,使优化加载RasterCodecs是调用RasterCodecs.StartOptimizedLoad之前信息或加载文档的页面RasterCodecs.StopOptimizedLoad当操作完成。StartOptimizedLoad将会通知RasterCodecs对象,所有后续RasterCodecs.GetInformation,RasterCodecs.GetInformationAsync,RasterCodecs.Load,RasterCodecs.LoadAsync方法将在相同的图像文件(或流),直到RasterCodecs.StopOptimizedLoad方法被调用。通过不同的文件或流在此操作将导致未定义的行为。加载不同的文件中间的操作,简单地创建一个新的实例RasterCodecs并使用它。
在优化加载使用RasterCodecs对象,它将创建、存储和重用使用的内部数据文件格式(比如PDF或文本)为特定文档文件或流处理所有必要的沟通。这个内部数据被释放时优化加载使用是关闭的RasterCodecs.StopOptimizedLoad或者当RasterCodecs对象是处理。
更高级的用法时加载的页面不出现在的寿命RasterCodecs实例。相反,它必须由不同的重用RasterCodecs对象(例如,当加载页面通过web服务)。在这种情况下,RasterCodecs.GetOptimizedLoadData可以用来获取当前的内部状态数据然后呢RasterCodecs.StartOptimizedLoad (CodecsOptimizedLoadData)叫将相同的优化负载在不同RasterCodecs对象。
注意,并不是所有的文件格式可以使用优化的负载数据。的做,不是所有文件格式支持/重建优化数据。对于这种类型的格式,RasterCodecs.GetOptimizedLoadData将返回零。
例如,下面的例子显示了一个行动在一个ASP。网络控制器的一个web服务,它允许用户从一个URL加载一个页面为PNG文件:
公共异步任务< ActionResult > GetPng (Uri Uri,intpageNumber)
{
/ /新RasterCodecs
使用(RasterCodecs编解码器=新RasterCodecs ())
{
RasterImage形象;
/ /加载页面作为RasterImage
使用(ILeadStream leadStream =等待LeadStream.Factory.FromUri (uri))
{
形象=等待编解码器。LoadAsync (leadStream pageNumber);
}
/ /保存为PNG
MemoryStream MemoryStream =新MemoryStream ();
使用(ILeadStream leadStream = LeadStream.Factory.FromStream (memoryStream))
{
等待编解码器。SaveAsync(图像、leadStream RasterImageFormat。Png, 0);
memoryStream。位置= 0;
}
image.Dispose ();
返回文件(memoryStream,“图像/ png”);
}
}
我们的目标是使用优化加载URL指向相同的文件。使用并发字典存储优化的数据加载。在现实的应用程序中,这应该被缓存机制,如下:
私有静态ConcurrentDictionary最后<字符串,CodecsOptimizedLoadData > _urlOptimizeLoadData = new ConcurrentDictionary最后<字符串,CodecsOptimizedLoadData > ();
公共异步任务< ActionResult > GetPng (Uri Uri,intpageNumber)
{
/ /新RasterCodecs
使用(RasterCodecs编解码器=新RasterCodecs ())
{
RasterImage形象;
/ /这个URI是否已经进行了优化
/ /将使用小写的URI作为键
字符串.ToLower关键= uri.ToString () ();
CodecsOptimizedLoadData uriOptimizedLoadData =零;
如果(! _urlOptimizeLoadData.TryGetValue(关键出uriOptimizedLoadData))
{
/ /没有优化的数据对于这个URI,因此一个新的开始
codecs.StartOptimizedLoad ();
}
其他的
{
/ /使用这个URI的优化数据,如果它存在
codecs.StartOptimizedLoad (uriOptimizedLoadData);
}
/ /加载页面RasterImage
使用(ILeadStream leadStream =等待LeadStream.Factory.FromUri (uri))
{
形象=等待编解码器。LoadAsync (leadStream pageNumber);
}
/ /如果一个新的优化的数据开始,它被RasterCodecs,然后保存
/ /字典
如果(uriOptimizedLoadData = =零)
{
uriOptimizedLoadData = codecs.GetOptimizedLoadData ();
/ /这可能是零,因为并不是所有的文件格式(a)支持优化的负载
/ /数据(b)支持获取或设置数据
如果(uriOptimizedLoadData ! =零)
{
/ /保存它
_urlOptimizeLoadData。TryAdd(关键,uriOptimizedLoadData);
}
}
/ /在这里必须停止优化加载。用这个RasterCodecs对象来保存
/ /到另一个位置
codecs.StopOptimizedLoad ();
/ /保存为PNG文件
MemoryStream MemoryStream =新MemoryStream ();
使用(ILeadStream leadStream = LeadStream.Factory.FromStream (memoryStream))
{
等待编解码器。SaveAsync(图像、leadStream RasterImageFormat。Png, 0);
memoryStream。位置= 0;
}
image.Dispose ();
返回文件(memoryStream,“图像/ png”);
}
}
的CodecsOptimizedLoadData类包含以下数据成员可以序列化,改造容易:
成员 | 描述 |
---|---|
CodecIndex | 整数表示内部LEADTOOLS编解码器使用数据(文件过滤器)指数。 |
GetData/setdata | 获取或设置内部状态数据作为一个字节数组。 |
上面的示例存储CodecsOptimizedLoadData对象字典。然而,类可以很容易地改造后保存到缓存系统。例如:
/ /从一个光栅编解码器:
CodecsOptimizedLoadData optimizedLoadData = codecs.GetOptimizedLoadData ();
/ /保存到用户定义的缓存,它需要保存整数(codecIndex)和byte[](数据)
如果(optimizedLoadData ! =零)
{
intcodecIndex = optimizedLoadData.CodecIndex;
字节[]data = optimizedLoadData.GetData ();
SaveToCache (codecIndex,关键数据);
}
和其它的方法:
intcodecIndex;
字节[]数据;
/ /加载它的用户定义的缓存
如果(LoadFromCache(关键出codecIndex,出数据)
{
/ /创建CodecsOptimizedLoadData并设置成RasterCodecs:
CodecsOptimizedLoadData optimizedLoadData =新CodecsOptimizedLoadData ();
optimizedLoadData。CodecIndex= codecIndex;
optimizedLoadData.SetData(数据);
codecs.StartOptimizedLoad (optimizedLoadData);
}
它曾经是CodecsOptimizedLoadData只包含管理成员,所以它不是一次性的。现在CodecsOptimizedLoadData可以包含非托管指针,所以现在可支配的类。来确定实例包含非托管(非)加载数据,检查CodecsOptimizedLoadData.UnmanagedData财产。
的行为CodecsOptimizedLoadData取决于过滤数据是平的,如下:
如果过滤数据是平的,CodecsOptimizedLoadData只有一个托管的字节数组。这并不需要处理和过滤数据的一个副本存储在里面RasterCodecs。当RasterCodecs实例或销毁RasterCodecs实例被另一个文件格式信息,筛选获得的数据仍然是有效的。此外,获得的对象不需要处理。
如果非过滤数据,CodecsOptimizedLoadData加载数据的吗CodecsOptimizedLoadData.UnmanagedData(类型IntPtr)。这IntPtr里面是一样的价值RasterCodecs。你必须得到这种类型的数据加载使用RasterCodecs.GetOptimizedLoadData(真正的)。GetOptimizedLoadData()和GetOptimizedLoadData(假)将返回null。只有RasterCodecs.GetOptimizedLoadData(真正的)将返回CodecsOptimizedLoadData类。
当你打电话RasterCodecs.GetOptimizedLoadData(真正的),你只得到一个窥视内部优化加载数据RasterCodecs对象。检索的对象可能已经在下列条件下处理:
在以上条件下,RasterCodecs创建的对象,它仍然拥有这个类中的非托管数据。所以,即使你获得CodecsOptimizedLoad一次性的数据对象,你不应该处理它。如果你处理它,你将使用的过滤数据失效RasterCodecs。这可能导致未定义行为。
用户可以得到优化通过调用加载数据的所有权RasterCodecs.DetachOptimizedLoadData。如果你叫RasterCodecs.DetachOptimizedLoadData,优化数据加载期间有效的应用程序,直到你处理它。
非托管过滤数据可以包含文件句柄或内部指针。因此,数据只在过程运行时有效。你不能把它给另一个进程,你不能使用它如果你停止并重新启动应用程序(比如web服务器的情况下)。
除了作参考之用,你用这个优化加载数据通过它作为参数StartOptimizedLoad (CodecsOptimizedLoadData)。
以下两段代码是等价的:
第一块
CodecsOptimizedLoadData optimizedLoadData = rasterCodecs.GetOptimizedLoadData (真正的);
rasterCodecs.DetachOptimizedLoadData ();
CodecsOptimizedLoadData optimizedLoadData = rasterCodecs.DetachOptimizedLoadData ();
如果你叫StartOptimizedLoad (CodecsOptimizedLoadData),你还有加载数据的所有权。调用RasterCodecs.StopOptimizedLoad或加载另一个文件/流不让你优化加载数据作废。你还必须处理它。
这是一种使用数据加载:
CodecsOptimizedLoadData optimizedLoadData;
CodecsImageInfo信息;
使用(RasterCodecs Codecs1 =新RasterCodecs ())
{
Codecs1.StartOptimizedLoad ();
信息= Codecs1.GetInformation (“sourcefile.docx”,真正的);
optimizedLoadData = codecs1.GetOptimizedLoadData (真正的);/ *获取数据* /
codecs1.DetachOptimizedLoadData ();/ * * /所有权
Codecs1.StopOptimizedLoad ();
}
循环的另一个这是创建多个线程,每一个从文件加载页面。注意,这将与文件,但不流,因为你不能有多个线程读取不同位置相同的流。
为(inti = 1;我< = info.TotalPages;我+ +)
{
使用(RasterCodecs codecs2 =新RasterCodecs ())
{
Codecs2.StartOptimizedLoad (optimizedLoadData);
使用(RasterImage图像= codecs2.Load(“源文件。多克斯”,我);
{
与图片* / / *做点什么
}
Codecs2.StopOptimizedLoad ();
}
}
optimizedLoadData.dispose ();/ *处理负载数据一旦你完成它* /