|
![]() |
![]() |
2008-3-9
星期日(Sunday)
晴
有一个星期没有更新blog,不过关于Reader还是有一些进展。预想的基本功能实现的差不多了,只是处理效率不高,包括上下翻页,自动保存退出位置等。
原来为了提高处理效率在后台生成下一页要显示的文字(onpaint中drawstring之后),但是触发onpaint事件的条件很多,比如激活输入法,阅读期间有人来短信等,事件一旦被激发,屏幕上的文字就自动重画下一页,于是我不得不把文字处理的代码挪回按键触发事件中去,考虑到小字体显示时要处理的数据量大,我又调大了2级字体设置,以提高效率,于是新的问题来了,如果机器默认没有开启ClearType功能的话,大字体显示的很难看,修正这一问题只有手动修改注册表来开启ClearType。自动保存退出位置功能的实现借助了外部文件的帮助,Reader在退出的时候会生成一个.res文件(resume,不是resource,呵呵),文件记录当前章节id及退出时页面开始位置字符的偏移量,这样在Reader读取UMD文件的时候会查找是否存在同名的.res文件,若有,读取退出位置信息并开始处理,若没有,显示第一章的第一页。接下来还要给程序添加选择章节的功能,实现这个很简单,下周找个时间会添加上。 说一下目前的不足:第一,运行效率不高,主要因为当初设计时考虑的不周,代码写多了以后又懒得大面积去改,基本功能实现后有机会会继续完善。第二,关于上翻页的问题,有两处,首先,当阅读过程中跨越了章节后,无法翻到上一章节的最后一页。其次,读取自动退出位置来显示文件,无法显示自动退出位置页的上一页。对于第一个问题,可以解决,但是这种情况发生的概率比较小,所以我没有去实现,对于第二个问题,目前还解决不了,因为上翻页的功能是通过存储已阅读页面的下标,在需要上翻页的时候取出再显示的方法来实现的,所以退出位置页以上的部分没有经过实际阅读是无法显示的。第三,没有了书签功能,怎么说呢,因为懒的弄了:(。 最后,因为这个程序是用.net cf写的,所以可执行文件不经过任何修改可以在PC上执行,对于今天越来越强大的PC硬件,这点数据量不算什么,算法再差,最终用户体验也差不到哪里去,但是对于移动设备,效率目前还是至关重要的,只有在这个时候才能真正理解到良好的算法和程序结构设计是多么重要。编译后的可执行文件上传到了Mofile ,提取码是6136393840649616 ,程序需要ICSharpCode支持,官方的UMD电子书制作器目录下有,就不上传了,使用时把Dll拷贝到可执行文件同一个目录下即可。完成章节选择功能,并整理下代码后,我会把源代码打包上传。...... 2008-3-2
星期日(Sunday)
晴
今天把分页的方法写了,完善了一下字符串显示长度计算方式,计入了回车换行的处理,按照原来的想法设置了缓冲字符串,即下一页将要显示的字符内容,因为这个缓冲是在当前屏幕绘制完成后在后台生成的,且本身的生成过程比较耗时,所以读起书来翻页不能太快,要一字一字慢慢地把本页读完-_-!,按目前的字体大小读完一屏需要30多秒左右的时间,如果这样的话那么后台处理还是能够及时完成的,不幸的是,如果使用者阅读能力惊人,10秒钟就读完一屏文字并按了翻页键,那么对不起,再等几秒吧···,虽然这是个很烦人的缺陷,但我觉得同时也是一个很好的功能,作为设计者我可以这样为自己辩护——这么做可以让人读书时不至于囫囵吞枣,达到强制学习的目的-_-!
目前显示上还存在一个问题,就是翻页后会出现字符绘制出了显示区的现象,不过打开文件的时候第一页显示是正常的,我考虑这是因为分页索引计算的问题,有可能是没考虑制表符及一些其他非可视字符的显示长度,造成字符串截取出现小范围误差所致,接下来会做几个小程序测试想法,找到原因并更正它。 PS:今天HH同学的忍者和双节棍把我着实震撼了一把,太有才了,这么吐字不清的歌居然也让你学会了,士别三日还当刮目相看···。看着电视上的歌词字幕我脑袋里再一次充满了字符串操作,My God,让这一切快点结束吧····...... 2008-2-27
星期三(Wednesday)
晴
下班回家后动手实验了一下中午的想法,相对于以前的实现,这个方法证明更可行一些,我终于在自己的手机上正确显示出了大于1M的文本,算是这几天可以一提的进展了,不过实际情况是,整体运行效果依然谈不上快,从打开大文件到显示在屏幕上要等将近10秒钟,因为是自制的软件,所以我自己能很理解,但如果用户是别人的话估计只能得到damn thing的评价:(.
提高效率的方法是修改Parser类,在二进制级别操作,甚至每次调用只返回需要的字符,而不是在Parser内生成所有的字符再处理,但这样做我觉得牺牲通用性,目前的类代码不用修改在PC上可以运行的很好,效率在强大的CPU面前并不是问题,而且这个东西对我来讲很耗费精力,如果真的去修改的话,也应该是基本功能都实现以后. 接下来需要做的是继续深化执行过程,运算中加入对回车,换行等转义的处理,让显示效果规范起来,实现上下翻页及书签功能.说一下关于书签的实现,我们之前分析过电子书生成器的代码,但一个完整的UMD文件的内容并不只是生成器生成的内容,没错,其他的数据是掌上书院软件在手机上写入的,这部分内容包括自动退出位置的记录及书签信息等,如果自己做个实验的话,你会发现同一本书在计算机上刚生成的时候与在手机上阅读了一部分以后的文件长度是不一样的,相差的字节即存储的上述信息.因为我没有精力去研究掌上书院的代码,我也就无法知道具体的存储细节,所以关于书签和自动保存功能的实现我打算借助外部文件实现,或者注册表. 今天实验的例子见下图,是直接写在Form上的,没有使用控件. ![]() ...... 2008-2-27
星期三(Wednesday)
晴
上班时走神想了下显示问题,突然想到一个解决方法,我并不打算在程序中提供能够在阅读期间更改字体的功能,那么对于固定字体,行高我是可以确定的,根据绘图区大小我就可以得到一个屏幕可以显示多少行,每一行显示区的宽度在PPC上固定是240个象素,那么我就可以得到一个屏幕上所有行字符串显示宽度的合(用totallineslen表示),然后开始遍历字符串,在循环中累加每个字符的宽度(当然字符不能是\r\n等转义符),当字符串显示宽度大于totallineslen,截取之前的字符串,并保留当前索引,然后在Onpaint里把截取的字符串画在屏幕矩形中,设置两个缓冲,分别存储上一页字符和下一页字符,以加快显示效率,上一页字符在翻页后保留,下一页字符在Onpaint执行结束后由后台继续分析生成.这种想法应该是可行,至少比之前用的方法效率高一些,一页一页的读比一次都处理完好一些.下班以后找时间实现看看效果先.......
2008-2-24
星期日(Sunday)
晴
这个周上班,很长时间生物钟调不过来,自由时间少了,人也昏昏沉沉,关于Reader的制作也没什么进展,写了一个字符串分割函数来处理显示问题,但和预想的一样,效率低下,在模拟器中读取一个没有分章节的长篇小说时模拟器几乎处于死机状态,宿主机的CPU占用率达到了50%(我目前是双核3G啊),等了将近一分钟也没有处理完,但也没有任何异常跳出,肯定是哪里有问题,但我想不出来,于是不得不放弃这种方法,我很奇怪类似的应用是怎么编出来的,如果程序思想一样的话那C++的原生代码就真的那么有效率嘛?这里有一点说的是掌上书院的PPC2.0版本使用Evc开发的,而3.0版本就换成了.net CF,而新版本远没有老版本好用,这也是我不喜欢3.0的原因,同时,这也说明用.net CF同样可以解决这个问题,只是我目前还不得要领.我猜测其实现是在字节级别进行的,而不是让机器做大量的字符串操作,但我现在实在没有精力去分析3.0版的源码了,我宁愿自己去实现一个可行的解决方法.......
2008-2-15
星期五(Friday)
晴
通过Parser能够得到大量的UMD文本,但是如何将这些文本以较高的效率显示出来成了问题,同时由于想加入全屏显示的选项,这更让问题复杂化.
最初的想法是将所有的文本根据屏幕宽度转换为由所有行组成的string[]型数组,然后用GDI+的drawstring画在矩形里,之所以按line分而不按page分也是考虑配合全屏幕的功能,但是这种想法很快就被自己否了,对于少量文本这样做还可以接受,但如果是那种好几百万字的小说,而制作者又不负责的不分开章节,那么程序将生成一个Length有几十万的数组,那么对于手机这种资源有限的设备,用托管代码来完成这个过程是一点都不明智的,毕竟Parser的处理过程已经比较耗时了.然后我转而去寻求别的办法,内置的textbox同样不可行,大文本显示不了,我甚至去翻了一些游戏制作的资料,但均无果. 目前我想比较可行的办法是设置一个缓冲区,分批读入文字并处理,这样可以减轻硬件的负荷,显示部分就直接用textbox控件,可是textbox里那个闪动的光标却无法通过继承去掉,这很让人不爽,可是不这样做就意味着又要用GDI+自己去画`````,要不就自己写个带缓冲的控件`````. 今天真是毫无进展的一天,我想现在软件开发中,制作那些非UI的东西相比UI部分工作量要小(用现成控件例外),当不得不自定义程序界面时,对于那些不熟悉界面编程且没有什么美感的人来讲,无异于恶梦,我现在就在做恶梦,而且还没醒过来```....... 2008-2-13
星期三(Wednesday)
晴
今天主要修改了原来的程序结构,写了一个Parser类来对读取功能进行封装,功能测试已经在自己的手机上面完成,比较理想,现在剩下来的事情就是如何把文本显示出来,显然textbox控件不能满足需求,只能用GDI+自己来画.还要继续完成分章节和书签等的功能,这些就相对好实现的多了.
![]() ...... 2008-2-12
星期二(Tuesday)
晴
按照对UMD文件结构的理解制作了一个Form程序,成功的读出了文件内容,这是一个功能实验模型,有很多没有考虑的地方,也有很多bug,经常会跳出异常,但这至少验证了前日画的结构草图,因为代码中reader的每一步操作都是依照草图结构进行的.下一步要对程序结构进行优化,不能像现在这样类C风格,至少应该写一个类把功能封装起来.在迁移至手机的过程中不可避免还要接触GDI+,这又是比较消耗时间的过程.
![]() ...... 2008-2-11
星期一(Monday)
晴
今天试着做几个程序来读取umd文件,以验证昨天画的结构图是否准确,发现一个问题,我在看代码时理解的writer.write(char)是以16位unicode编码写入的,即占用两个字节,但实际情况是,只占用了一个字节,这导致我以后读取的数据都和预期不一致,试着按单字节跳过char再读取,结果符合预期.后来查了一些资料,没有类似的例子,不过查到了C#字符变量还有单字节,双字节之分,并不是原来想的统一双字节,当encoding编码定义为默认的时候遇到单字节字符变量他会只生成一个字节存储,双字节(如汉字)则分配两个字节,或者可以显式的用Unicode对单字节变量处理一下,那么单字节变量也会变成双字节的.用程序验证了一下,的确是这样.所以正确的结构看起来应该是:
![]() 修改后的Word文档已经更新并上传,提取码更新为7081447387578310 关于这个问题我在msdn里找了好久也没找到满意的说法,毕竟官方资料里char是16位的,为什么写入文件变成单字节了?还是不解....... 2008-2-11
星期一(Monday)
晴
Make()方法生成UMD文件,看这个方法是一个很容易让人烦躁的事,那么多的循环,那么多的write,还有一堆转义,不过既然下决心搞清楚这个东西,还是硬着头皮把它看完了,在看的过程中记下了笔记,并且画了一张文件结构图,类似下图:
![]() 把整个文件结构写清楚比较麻烦,就不在blog上帖全了,我做了个word文档上传到Mofile上,提取码为9627528031944304,如果需要的话可以下载看一下,还不能完全肯定所有的信息是正确的,但应该准确率很高了....... |
||||||||||||||||||||||||||||||||||||||||||||||||||