![提词器原理分析与技术实现_第1页](http://file2.renrendoc.com/fileroot_temp3/2021-11/4/2902e336-1c2e-46f6-9a93-0ce696489e91/2902e336-1c2e-46f6-9a93-0ce696489e911.gif)
![提词器原理分析与技术实现_第2页](http://file2.renrendoc.com/fileroot_temp3/2021-11/4/2902e336-1c2e-46f6-9a93-0ce696489e91/2902e336-1c2e-46f6-9a93-0ce696489e912.gif)
![提词器原理分析与技术实现_第3页](http://file2.renrendoc.com/fileroot_temp3/2021-11/4/2902e336-1c2e-46f6-9a93-0ce696489e91/2902e336-1c2e-46f6-9a93-0ce696489e913.gif)
![提词器原理分析与技术实现_第4页](http://file2.renrendoc.com/fileroot_temp3/2021-11/4/2902e336-1c2e-46f6-9a93-0ce696489e91/2902e336-1c2e-46f6-9a93-0ce696489e914.gif)
![提词器原理分析与技术实现_第5页](http://file2.renrendoc.com/fileroot_temp3/2021-11/4/2902e336-1c2e-46f6-9a93-0ce696489e91/2902e336-1c2e-46f6-9a93-0ce696489e915.gif)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、播音提词器的原理分析和技术实现1. 提词器应用概述我开发的一个产品想实现很多显示设备的同屏显示效果,查阅资料的时候发现播音提词器也是其应用之一,那就顺便一起研究了吧。笔者很长时间没有开发程序了,错误的地方请广大码友多多批评指正。电视提词器是常用于电视播音、采访工作中的专用设备。其使用场景是播音员在播音的时候,需要正视前方,流畅说出待播内容。由于播音具有不确定性,播音员很难准确记住整片文件,因此需要借助外部协助。外部协助包括语音导播和图像导播:语音导播是指导播人员在幕后手持文稿阅读,声音传输到播音员所用的耳机,播音员根据导读声音播出。图像导播:是指在播音员前方防止较大屏幕的显示屏,用于显示待播文
2、稿,文稿调整显示内容,播音员阅读内容。语音导播和图像导播各有弊端,语音导播受人为影响较大,例如导播要控制播音进度,并且导播的时候不能出现意外状况(打喷嚏、注意力不集中等),图像导播往往需要借助多种设备,成本较高。高质量图形设备层出不穷,为了确保播出质量,图形提词器应用越来越广泛。因此导播系统虽然看似简单,但是如果要实现高质量的导播效果,需要精心设计。本文主要讨论图像方式的导播,通过需求和技术分析,提供新技术广泛应用下的最优解决思路。2. 图像提词器发展情况图像提词器发展经历了三个阶段:模拟信号提词器、计算机信号提词器和网络提词器。2.1 模拟信号提词器模拟信号提词器是最早的图像提词器技术,其原
3、理是播音员前方放置待播纸质文稿,文稿正上方置摄像仪器,仪器所拍信号通过线路传输到播音员正前方约5米的显示屏,显示屏所显示的为镜像图像,需要经过一个45°的反光玻璃纠正,从而看到正像,播音员阅读正像图片播出。其示意图如下:图像在上述环境中显示的图像如下:播音员阅读反向文字非常吃力,需要模拟信号显示器进行像素偏转处理现镜像显示其实很简单,只需要对显示器电路作简单的修改,将显像管的行偏转线圈两个接线头调换一下,即可实现图像的镜像显示。这种方案有如下特点:1、 播放进度掌控在播音员手中,控制自如;2、 原理简单,几乎全部基于硬件设备,线路清晰;3、 硬件刷新率较高,但是图像增强显示,容易对播
4、音员眼部造成伤害;4、 播音的时候,播音员手部需要换搞,动作需要雅观;5、 播音的时候需要较大屏幕,对焦比较麻烦;6、 造价较高;2.2 计算机信号提词器随着计算机办公普及,电视文稿产生、传输实现了无纸化,使用针对电子文档的提词器是大势所趋,模拟信号提词器也逐步由模拟信号提词器发展成计算机提词器,播音员只需要通过鼠标或控制器就可以灵活控制文稿的显示。同时由于显示技术的发展和对提词器轻量化和移动性,便携性的要求,传统的CRT提词器已经逐渐被淘汰,转而大量使用液晶显示器做为显示单元。新型电脑提词器的组成如下图所示:液晶显示器不再具有偏转线圈扫描单元,市售的液晶显示器也都无法通过简单地修改电路实现图
5、像的镜像显示。目前实现液晶显示器提词的方法基本有两种:一种方法是使用专用的硬件VGA镜像发生设备器,实现显示器信号的镜向输出,但这种设备基于硬件,成本高,一旦损坏,将难以及时修复。第二种方法是使用双显卡或双头显卡,利用软件实现副显卡与主显卡显示内容的镜向,实现方法是使用专用软件辅以一种专用的镜像显示字库并通过改变文字的显示顺序来实现文字的镜向显示。目前市面基于这种方案的提词器具有如下特点:1、 使用通用的计算机硬件,维修更新方便,成本低2、 必须使用专用软件,文稿兼容性差,不能兼容常见的WORD,WPS,PDF等文稿格式;3、 更无法实现图文同时显示;4、 使用专用字库,仅能实现中文或英文提词
6、,无法实现中英文混合显示;5、 少数民族等需要纵向显示的文稿,播音台无法正常使用;为解决上述两种方案的弊病,需要设计出一种使用通用硬件,同时又能直接支持各种软件的提词器系统。第二套方案的硬件设计具有很强的通用性,目前主流PC均可安装双显卡或单片双头显卡,普通显卡由于是民用产品,价格便宜,来源广泛,数百元即可购得,因此这将是一种极为廉价的高可靠性电脑提词器信号输出方案,值得采用,因此提词器系统硬件部分应该选用这种方法。 关键的难点在于如何用软件实现副显示器对主显示器的镜像滚屏输出,同时又要兼容众多的文档格式。事实上,各种文档格式都有成熟的软件可以打开,并可以在
7、鼠标控制下实现自动滚屏和手动滚屏,例如Microsoft Word,只要打开文档后,点击鼠标滚轮键,即可控制滚屏速度和方向,同时显示字号、字体的大小均可任意调节。因此,多文档格式滚屏的实现,完全可以利用各类文稿软件自身的功能来实现。问题就简化为如何将主显示卡上显示的内容实时地水平镜像复制到副显示器上。本文重点讲述如何利用简易设备,采用合理的软件技术,解决上述弊端,实现高质量的屏幕镜像复制效果。2.3 网络提词器随着互联网直播台、现场录播、讨论式播出的不断流行,需要播音软件具有更复杂的、控制功能,实现多人播出,并在播出的时候插稿、临时修改播音词、合理引导播出等。网络提词器方案一般是根据计算机提词
8、器的第二套方案,对提词器的内容同步、显示控制等进行功能改进,实际上是软件提供了更加复杂的网络控制功能。网络提词器的原理如下图所示:上图所示播音员的的计算机仍是核心,播音员可以操控播音计算机的播放进度,而编辑员计算机通过软件获取播音员当前的播出内容,并进行编辑,完毕后将新内容同步到播音员计算机,达到插播效果。上述方案中,编辑员获取播音员当前播出内容和编辑非常容易,难点在于在播音员正常录播的情况下如何实现屏幕加载。网络软件技术要求高,而且需要安全操作,因此软件造价相对较高,但是其强大的功能对于大型播音台非常适用。3. 计算机和网络提词器需求分析通过对提词器的发展分析,可以看出目前市场对提词器的需求
9、大致如下:3.1 文稿引入文稿引入是指提词器软件应具备自建内容和从外部获取内容的能力。由于提词器的展示样式是其运行前可以设置的,因此软件所管理的内容应当是文本内容,文稿引入要求可以打开常用格式的稿件,并提取其文本内容。常用的文稿样式有TXT、Microsoft Word、WPS、PDF、HTML等。自建文稿是指用户可以在软件新建一篇文稿,由于软件管理文本内容,因此建议新建文稿的格式为TXT文档。3.2 二次编辑二次编辑是指播音人员在播音前的阅稿过程中如果发现稿件有错误或已经装入的稿件需要临时调整,可以通过软件及时调整,不影响播出。3.3 题词效果设置播音的时候,需要对题词文本进行展示样式的设置
10、和字幕展示方式设置,以达到最好的提示效果。样式的设置包括对字体、字号、文字颜色、文字背景颜色、行间距、字间距、段落间距等;字幕展示方式是指对不同的播音习惯进行文字横排和纵排展示,横向滚动和纵向滚动展示,文字排版方向和字幕滚动方向互相配合使用,一般当字幕自下向上纵向滚动的时候文字横向自上向下排版,字幕自上向下滚动的时候文字自下向上排版,字幕自左向右滚动的时候文字自右向左排版,字幕自左向右排版的时候文字自左向右排版。以下列出部分效果示意:横向字幕水平镜像的示意效果横向字幕垂直镜像的示意效果横向字幕的自上向下滚动示意效果纵向字幕的水平镜像效果示意纵向字幕的垂直镜像效果示意3.4 镜像支持两个显示器镜
11、像显示,包括屏幕复制、水平镜像和垂直镜像。3.5 进度控制进度控制是指字幕在运行过程中,应当可以展示出字幕开始的时间、已经运行的时间、剩余时间、进度百分比等信息,便于播音员了解当前进度情况。播音员可以根据当前进度情况使用多种方式进行进度调整,包括可以鼠标滚轮、游戏手柄、脚踏开关等调整滚动速度和当前进度,并可以随时控制暂停、回复滚动等操作。3.6 插播插播是指字幕已经装载内容并且正在滚动的时候,其它程序可以增加、删除正要播出的内容,并将最新的内容更新到正在播放的屏幕,更新的时候屏幕不会闪烁。3.7 语言播音软件要应对不同语种的播音需要,例如英语、汉语、日语、韩语、哈萨克等等,要求软件界面、提示信
12、息和字幕内容支持多语种,便于播音员顺利操作软件和播音。4. 技术实现方法了解上述需求后,可以想象最好的实现效果好比玩游戏一样,在进行内容的检查后进行样式设定,然后开始执行字幕,执行过程中播音员就像游戏中的线路跑动一样,调整跑动速度,如果已经连接了扩展显示器,扩展显示器可以随时镜像显示。实现上述效果看似简单,要达到游戏效果绝非易事,有很多难点:ü 字幕排版灵活,如对较大篇幅的文字根据设置进行横向和纵向排版;ü 镜像屏幕需要恒定的速度,而在Windows操作系统下很难得到;ü 字幕滚动过程中持续占用处理器资源,避免字幕滚动过程中出现闪烁;ü 支持更多的外部驱
13、动,包括游戏手柄等;笔者访查市面上绝大多数提词器,其使用的技术分为以下几种:方案1: 创建两个窗口,一个全屏运行在主屏幕,另一个全屏运行在副屏幕。主屏幕运行正像显示的字幕,副屏幕镜像显示主屏幕的内容。主屏幕字幕排版采用文本控件实现,然后将文本控件图像贴图到副屏幕,建立一个定时器,定时调整文本控件滚动条的位置,并将所产生的最新图像贴图到副屏幕的窗口。在实现的时候有很多问题要考虑,例如大文件的快速装载,文本控件的滚动条隐藏等,需要主屏幕的软件隐藏文本控件,并将文本控件的显示图像拷贝出来,根据当前位置粘贴到预置好的3个图片框。该方法使用VB或者VC开发比较适合,VB开发技术门槛低,比较适合工具类软件
14、开发,同时可以调用Windows API实现强大的功能,并且具有很高的运行效率,当然如果做到更优秀的功能,需要采用VC,VC在文本处理、图像处理、硬件控制等方面都具有非常优秀的能力,但是VC开发往往需要更高的成本。方案2:同样是创建两个窗口,文字排版依靠系统API函数,API函数根据设置的效果将文字打印在主窗口屏幕,主窗口屏幕打印完毕后,将主窗口所有内容镜像显示到扩展屏幕的窗口。该方案的排版功能很难实现,例如绘制某一时刻的字幕效果,需要先知道整体高度,当前运行的位置,下一刻速度等。方案3:如同方案2,不同的是副屏幕不再是镜像显示主屏幕的图像,而是文字依靠可镜像的字体,直接镜像显示。其优点是运行
15、效率比方案2高一些,缺点是对字体的控制相当麻烦,投入非常大而收获很小,只能使用很少量的字体。以上方案有很多缺陷:1. 方案1和方案2依靠全屏贴图实现屏幕镜像,肉眼的舒适切换频率在100毫秒,而双屏整屏幕绘制(StretchBlt),往往会超出(目前市场的中配显示器,整平刷新需要40-70毫秒,如果加上软件处理的损耗,往往会达到120毫秒以上),顿挫感很强;2. 较大文件的字幕需要动态将文字转化为图片,如果要实现无刷新效果,必须使用内存双缓冲绘图技术,该技术比较复杂,即使使用了该技术,若使用了较低配置的显示器或主机,仍无法达到效果;3. 实现纵向字幕是非常艰巨的工程;4. 若要实现多角色播音(加
16、背景颜色),性能会大幅降低;5. Timer控件有很多缺陷,其主要作用是定时触发,如果处理时间超出timer的设定频率,屏幕滚动时快时慢,影响播出;6. 主屏幕和扩展屏幕尺寸不一致的时候,即放大和缩小显示,出现排版混乱;为了解决上述问题,笔者决定尝试采用较新的技术:使用C#开发,运行在Windows7+IE10及以上版本。为什么必须要采用C#开发呢?因为C#运行在.net CLR上面,已经提供了性能较好的绘图技术,而且获取外部文档的技术相对简单,而运行在IE10是因为IE10的超文本渲染效果是最好的,滑动非常细腻,而且支持超大文件,而且我想使用CSS3实现部分排版功能。总之IE的技术投入是非常
17、大的,人家是超文本展示的高手,仔细发掘肯定能满足我们的需求。众所周知,现在的笔记本通常是Windows7操作系统,IE10通常运行在Windows7上,笔记本通常可以直接连另一个扩展屏幕,无需额外的硬件投入。当然如果要运行更流畅,建议扩展显示器采用刷新率较高的,而且内存4G以上,CPU 2GHZ以上,现在主流笔记本都可以达到。说了这么多,该技术环节登场,针对需求,列出主要实现办法。本文的代码主要是测试代码,有些是从往上拷来的,是我都运行过,是可用的。4.1 打开外部文件并提取文本打开外部文本包括提取Word、WPS、PDF的文本内容,按照原有的段落组织。C#获取Word内容需要引用Micros
18、oft Word 12.0 Object Library类库,实现方法如下:Word.ApplicationClass wordApp=new ApplicationClass(); object 表示Word的路径object nullobj=System.Reflection.Missing.Value; Word.Document doc = wordApp.Documents.Open(5.ref file, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj
19、, ref nullobj, ref nullobj, ref nullobj, ref nullobj); doc.ActiveWindow.Selection.WholeStory(); doc.ActiveWindow.Selection.Copy(); IDataObject data=Clipboard.GetDataObject(); String doctext=data.GetData(DataFormats.Text).ToString(); doc.Close();打开WPS文档的代码如下:object WpsApp;object args =
20、 new object1;Type wpsAppName;string progID = "Wps.Application"wpsAppName = Type.GetTypeFromProgID(progID); /创建一个WPS实例WpsApp = Activator.CreateInstance(wpsAppName);args0 = true; /设置为可见wpsAppName.InvokeMember("Visible
21、", BindingFlags.SetProperty, null, WpsApp, args); /得到Documents对象Object wpsDocs = wpsAppName.InvokeMember("Documents", BindingFlags.GetProperty, null, WpsApp, null); /设置关键参数即可,例如: 在打开的方法中,只要指定打开的文件名与是否可见args
22、60;= new object15;args0 = "C:/Demo.wps"args11 = true; /打开C盘下的Demo.wpsObject wpsDoc = wpsAppName.InvokeMember("Open", BindingFlags.InvokeMethod, null, wpsDocs, args);args = new object3;/下面就可以从doc对
23、象获取文本了打开pdf请注意,pdf分为单层pdf和双层pdf,单层pdf是由图片组成的每一页,双层pdf是每一页的图片上面覆盖有文字,软件只能打开双层pdf,实际是读取所覆盖的文字部分,如果想从图片获取文字,只能用OCR技术了,对这个软件来说没有必要。打开双层pdf的代码如下:添加一个iTextSharp的引用,iTextSharp是一个开源的PDF操作类库。string xieyi = "" fi = new ();StreamReader sr = fi.OpenText();xieyi = sr.ReadToEnd();sr.Close();return xieyi
24、; 文本读取以后要写入到一个新的txt文件里面,以备后面编辑的时候用。4.2 展示、编辑文本展示文本是指从读取后生成的txt文件中按照段落取出来数据,并呈现给播音人员检查。从txt文件中读取内容比较简单,不再粘贴代码了。从txt文件中读取的文本按照段落存储在String数组当中,数组作为DataGridView的数据源呈现。在这里我们需要新建一个List< CaptionItem >对象作为DataGridView的自定义数据源。其中CaptionItem是每一个数据项,其字段包括。Text(文本内容 ,即每一个段落)、FontName、FontSize、FontColor、Sec
25、tionPadding、RowPadding、BackGroundColor、Alignment等。这个对象建立以后,就将我们读取的String数组封装为List<CaptionItem>对象。将该数据绑定到DataGridView即可显示。绑定代码如下:/绑定GW.DataSource = null;BindingList<CaptionItem> bindsource = new BindingList <CaptionItem>(DataFactory.getDataSource();GW.DataSource = bindsource;绑定以后我们每
26、一行就可以取出来内容展示了:然后我们完善双击事件,实现快速修改内容、文字样式、背景颜色、间距等参数设置,难度相当于农民种菜。下一步我们继续完善其它编辑功能,例如删除行、增加行、复制剪切粘贴行、格式刷等等,代码较多就不帖了,放上编辑的撤销和恢复操作代码吧:public void UnDo() SerRow undoRow = un.Undo(); if (undoRow = null) return; /当Ì¡À前¡ã值¦Ì压1入¨?REDO堆?栈? CaptionItem catchedRow = new Capt
27、ionItem(DataFactory.getDataSource()undoRow.RowIndex); un.setRedo(new SerRow(undoRow.RowIndex,0,catchedRow); /执¡ä行DUNDO exeUndoRedo(undoRow); /定¡§位?到Ì?被À?恢?复¡ä的Ì?行D if (undoRow.Tag = 0) gridView.CurrentCell = gridView.RowsundoRow.RowIndex.Cells0; else if (
28、undoRow.Tag = 1) gridView.CurrentCell = gridView.RowsundoRow.RowIndex-1.Cells0; else if (undoRow.Tag = -1) gridView.CurrentCell = gridView.RowsundoRow.RowIndex + 1.Cells0; undoControl.Enabled = un.IsUndoPossible(); redoControl.Enabled = un.IsRedoPossible(); public void ReDo() SerRow redoRow = un.Red
29、o(); if (redoRow = null) return; CaptionItem catchedRow = new CaptionItem(DataFactory.getDataSource()redoRow.RowIndex); un.setUndo(new SerRow(redoRow.RowIndex, 0, catchedRow); exeUndoRedo(redoRow); /定¡§位?到Ì?被À?恢?复¡ä的Ì?行D gridView.CurrentCell = gridView.RowsredoRow.
30、RowIndex.Cells0; undoControl.Enabled = un.IsUndoPossible(); redoControl.Enabled = un.IsRedoPossible(); 最后交代一下,如果用户希望我们的单元格能够换行显示,而且根据我们设定的文字大小换行显示,我建议不要使用DataGridView的AutoHeight等属性,交给重绘事CellPaint件来做。BS微软的开发,AutoHeight属性用了以后,加载叫个超级慢。if (e != null) if (e.ColumnIndex = 0) && (e.RowIndex >= 0
31、) AppTools.updateRowStyleByData(GW, e.RowIndex); if (WarpDToolStripMenuItem.Checked) / Size size = e.ClipBounds.Size; string Value = "" if (e.Value = null) return; Value = e.Value.ToString(); if (String.IsNullOrEmpty(Value) Value = "无" Captions.AppTools.hhString str = new Caption
32、s.AppTools.MrString(Value, titleColumnWidth, size.Height, e.CellStyle.Font, e.Graphics); GW.Rowse.RowIndex.Height = (int)str.height; else GW.Rowse.RowIndex.Height = (int)e.Graphics.MeasureString("幕", e.CellStyle.Font).Height; 至此内容编辑的功能实现的差不多了,不过最后建议增加一项功能,就是能够将当前编辑的文字、样式保存为我们自己的文件,下次可以直接调出
33、来这个文件,不用再编辑文字和设置样式了,够人性化吧?我们自己去规定文件样式把,编码采用Unicode,先生成文件内容:IList<String> styledStringList = new List<String>();List<CaptionItem> dataSource = DataFactory.getDataSource();foreach (CaptionItem dataItem in dataSource) String styedRow = "" Font font = dataItem.getFFont(); sty
34、edRow = dataItem.文?本À? + "t" styedRow = styedRow + "" styedRow = styedRow + "fontName:" + dataItem.SFont + "," styedRow = styedRow + "fontSize:" + font.Size + "," styedRow = styedRow + "fontColor:" + dataItem.getFontColor() +
35、 "," styedRow = styedRow + "fontBold:" + font.Bold.ToString().ToLower() + "," styedRow = styedRow + "fontItalic:" + font.Italic.ToString().ToLower() + "," styedRow = styedRow + "fontStrikethru:" + font.Strikeout.ToString().ToLower() + "
36、;," styedRow = styedRow + "fontUnderLine:" + font.Underline.ToString().ToLower() + "," styedRow = styedRow + "aligns:" + dataItem.对齐 + "," styedRow = styedRow + "bgColor:" + dataItem.getBgColor_HTML() + "," styedRow = styedRow + "
37、margin:" + dataItem.间距¨¤ + "" styledStringList.Add(styedRow);return styledStringList;写入文件的代码:if (System.IO.(fName) (fName);using (StreamWriter sw = new StreamWriter(fName, false, Encoding.Unicode) oreach (String strItem in styledDataArray) sw.WriteLine(strItem);4.3 字幕排版设置字幕排
38、版是字幕软件的重点了,我们既然决定让IE来帮我们实现排版,那排版后的文件格式就应该是HTML了,字幕排版的重点是生成合适的HTML文件,并借助WebBrowser控件展示出来,达到用户想要的字幕效果。有童鞋问了,既然我们要生成HTML,为什么刚才要保存成我们自己设定的文件格式呢?因为我们可以继续写功能,让该软件可以打开这个带有格式的文件,而采用HTML格式保存,我们下次解析里面的内容和格式相对困难。字幕排版设置是指告诉系统,以后运行字母的时候,默认生成哪种样式的字幕。样式包括水平字幕自上向下滚动、水平字幕自下向上滚动、垂直字幕自左向右滚动、垂直字幕自右项左滚动。设置部分代码简单就不列出了。4.
39、4 字幕预处理该功能是指用户在运行字幕前,需要根据字幕排版设置的参数,生成相应的HTML文件。生成的HTML有如下关键部分:按照我们之前设定的内容、内容样式,段落样式生成基本段落HTML代码,给段落HTML代码附加样式生成适合字幕方向的代码。生成基本的HTML段落代码比较简单:StringBuilder sb = new StringBuilder();sb.Append("<div style="width:" + screenSize.Width.ToString() + "" > rn");sb.Append(&qu
40、ot;<div style="height:" + (screenSize.Height).ToString() + "px" ></div>rn");if (direction = 0) foreach (CaptionItem item in DataFactory.getDataSource() String css = getCss_H(item, direction); sb.Append("<div " + css + ">" + item.文本 + &qu
41、ot;</div>" + "rn"); else if (direction = 4) for (int i = DataFactory.getDataSource().Count - 1; i >= 0; i-) CaptionItem item = DataFactory.getRow(i); String css = getCss_H(item, direction); sb.Append("<div " + css + ">" + item. 文本 + "</div>
42、;" + "rn"); sb.Append("<div style="height:" + (screenSize.Height).ToString() + "px" ></div>rn");sb.Append("</div> rn");return sb;段落样式代码如下:/获?得Ì?横¨¢向¨°排?版ã?的Ì?CSS样¨´式º?private St
43、ring getCss_H(CaptionItem item, int direction) StringBuilder sb = new StringBuilder(); String dirStr = "" if (direction = 4)dirStr = "writing-mode:lr-bt;text-align:left; " sb.Append("style="" + dirStr); Font font = item.getFFont(); if (!String.IsNullOrEmpty(font.Na
44、me) sb.Append("font-family:'" + font.Name + "'");sb.Append("font-size:" + font.Size.ToString() + "pt;");if (font.Bold) sb.Append("font-weight:bold;");if (font.Italic) sb.Append("font-style:italic;");if (font.Strikeout) if (font.Unde
45、rline)sb.Append("text-decoration:line-through underline;"); elsesb.Append("text-decoration:line-through;");else if (font.Underline)sb.Append("text-decoration:underline;"); String alignStr = "" if (item.对齐.Equals("")alignStr = "left" else if
46、 (item. 对齐.Equals("")alignStr = "right" elsealignStr = "center" sb.Append("text-align:" + alignStr + ""); sb.Append("color:" + item.getFontColor() + ""); sb.Append("background:" + item.getBgColor_HTML() + "");
47、sb.Append("padding-top:" + item.间距/2+ "px;padding-left:0px;padding-right:0px;padding-bottom:" + item. item.间距/2+ "px; margin:0px;"); sb.Append("""); return sb.ToString();需要留意的是writing-mode:lr-bt属性,它用来决定我们的Div里面的文字排版方向,只有高版本的IE才能够支持。另外需要留意的是字幕开始的时候,是总最边缘慢慢
48、移入相对方向的,需要生成一个满屏的空DIV先占位。以上是横向排版的部分生成代码,纵向排版字幕以此类推,主要是修改writing-mode:lr-bt属性。当然入到反向滚动的字幕,生成HTML的时候,对List< CaptionItem>按照自底部向顶部依次输出。4.5 字幕窗口字幕窗口主要实现的是加载HTML代码,加载控件是WebBroswer。WebBroswer的Navigate方法用于接在HTML代码。有同学要问了,为什么不将生成的HTML代码直接传递给WebBroswer而是生成HTML文件让WebBroswer加载呢?因为笔者经过测试,WebBroswer直接加载HTML
49、代码,不太好触发DocumentCompleted事件,我们需要对DocumentCompleted进行监控,等待WebBroswer全部加载完毕再滚动字幕,有一个暂短的停留。if (WB.ReadyState < WebBrowserReadyState.Complete) return;timerScroll.Interval = (DataFactory.getDataSource().Count+1)/2+1000;/加¨®入¨?鼠º¨®标À¨º点Ì?击¡Â事&
50、#186;?件tthis.WB.Document.MouseDown += new HtmlElementEventHandler(WB_mouseclik);WB.Document.Focusing += new HtmlElementEventHandler(WB_Focus );timerScroll.Enabled = true;这里面用到了Timer,实际上将来Timer只执行一次,之所以用它,是想程序不假死的等待,当然你可以有别的实现办法。那么Timer是做什么的呢?private void timerScroll_Tick(object sender, EventArgs e)
51、timerScroll.Enabled = false; panelLodding.Visible = false; WB.Visible = true; Rectangle wbScrollRectangle = this.WB.Document.Body.ScrollRectangle; /如¨?果?没?有®D镜¦Ì像?显?示º?器¡Â,ê?镜¦Ì像?按ã¡ä钮£¤无T法¤¡§使º1用®? i
52、f (Contants.MONITOR_DIR != 3) showMirrorWindow(); Thread.Sleep(100); /初?始º?化¡¥屏¨¢幕?滚?动¡¥参?数ºy captionThread = new CaptionThread(); captionThread.setCaptionArgs(this, wbScrollRectangle, panelCenter.ClientRectangle, new ScrollBackHandler(RefreshBK), new ScrollBa
53、ckHandler2(scrollBackInvok), new ScrollBackHandlerMirror(RefreshBKMirror); theThread = new Thread(new ThreadStart(captionThread.startScrolling); theThread.Name = "字Á?幕?线?程¨¬" + DateTime.Now.ToShortTimeString() + " 创ä¡ä建¡§" theThread.Start()
54、; startScrollTime = DateTime.Now; 它的作用是启动一个字幕线程,专门用来处理滚动的事情。有同学会问,为什么要启动另一个线程?因为我想获得更稳定的速率。while (!blnScrollingStop) && (H < sourceWidth) if (!Contants.PAUSE) | (blnScrollingPause) Application.DoEvents(); continue; DateTime t = DateTime.Now; /监¨¤听¬y主¡Â线?程¨
55、72;是º?否¤?让¨?关?闭À?该?线?程¨¬ if (H = 0) Thread.Sleep(1000); Point speedPoint = AppTools.getSpeed(Contants.CAP_SCRLLSPEED); AppTools.AccurateSleep(speedPoint.X ); H = H + speedPoint.Y; /主¡Â绘?图ª?事º?件t int offset = (sourceWidth - H - parentRectangle.Width);
56、 /横¨¢向¨°偏?移°?的Ì?数ºy值¦Ì if (offset < 0) offset = 0; if (H >= sourceWidth - parentRectangle.Width) H = 0; /通ª¡§知a主¡Â线?程¨¬刷¡é新? if (!(frmParent.IsDisposed) try frmParent.Invoke(scrollBackHandler, new Point(o
57、ffset, 0); frmParent.BeginInvoke(scrollBackHandler2, new Point(offset, 0), t); if (Contants.MONITOR_DIR < 3) frmParent.Invoke(scrollBackHandlerMirror, new Point(offset, 0); catch(Exception) /DateTime t2 = DateTime.Now; /TimeSpan ts = t2 - t; /Console.WriteLine(ts.Milliseconds); 该现成的主要作用是提供一个稳定的速率
58、,到了指定的时间让WebBroswer控件的滚动条改变位置,从而达到滚动效果。需要留意的是我使用了While循环,如果不释放控制权,程序很可能假死,如果采用DoEvents释放,操作系统的忙碌程度对程序将会造成很大影响,从而造成闪烁,那么我就写一个非模态等待函数,函数的主要功能是扔程序消息,即让程序不假死(响应鼠标键盘操作,还能高效执行滚动)。/非¤?模¡ê态¬?延¨®迟¨´ public static void AccurateSleep(int a_i4MSec) Int64 t_i8Frequency = 0; Int64 t_i8StartTime = 0; Int64 t_i8EndTime = 0; double t_r8PassedMSec = 0; API.MS
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025至2030年中国汽车皮带轮罩壳数据监测研究报告
- 2025至2030年中国固定回转支撑式起重机数据监测研究报告
- 2025至2030年中国中医仪器设备数据监测研究报告
- 2025年中国金刚布纹砖市场调查研究报告
- 2025至2031年中国高刚玉制品行业投资前景及策略咨询研究报告
- 2025至2030年中国金花米黄大板数据监测研究报告
- 2025至2030年中国超声波孔壁测定仪数据监测研究报告
- 2025至2030年中国色散分析仪数据监测研究报告
- 2025至2030年中国线阵超声诊断仪数据监测研究报告
- 2025至2030年中国现场直流电流校验信号发生器数据监测研究报告
- 2024公路工程施工安全风险辨识与管控实施指南
- 浙江省嘉兴市2023-2024学年高一上学期1月期末考试政治试题
- 新疆2024年新疆和田师范专科学校招聘70人笔试历年典型考题及考点附答案解析
- 【正版授权】 ISO 15978:2002 EN Open end blind rivets with break pull mandrel and countersunk head - AIA/St
- 2024时事政治考试题库(基础题)
- 2024山西文旅投资集团招聘117人公开引进高层次人才和急需紧缺人才笔试参考题库(共500题)答案详解版
- 小学校本课程教材《趣味数学》
- 干细胞疗法推广方案
- (2024年)电工安全培训(新编)课件
- mil-std-1916抽样标准(中文版)
- 《社区康复》课件-第七章 脑瘫患儿的社区康复实践
评论
0/150
提交评论