About

<#TEMPLATE_INCLUDE_NINEPAGE_ABOUTME#>
  • Mar

    31

    第一个:alivePDF

    官方地址:http://alivepdf.bytearray.org/

    谷歌地址:https://code.google.com/p/alivepdf/

    第二个:purePDF

    谷歌地址:https://code.google.com/p/purepdf/wiki/Examples

    github 地址:https://github.com/sephiroth74/purePDF

    Mar

    27

    使用 FFmpeg 合并音频和视频

    • 0 Comments
    • Miscellaneous
    -isync -f s16be -<PATH TO SOUND FILE> -<PATH TO VIDEO FILE> -acodec libfaac -ab 128 -vcodec copy

    参数说明:

    • -isync 它告诉 FFmpeg 将视频与音轨同步。
    • -f s16be 它告诉 FFmpeg 音轨的样本是按大端法作为 16 位整数编码的。
    • -i <PATH TO SOUND FILE> 它用于传递声音文件的路径。
    • -i <PATH TO VIDEO FILE> 它用于传递视频文件的路径。
    • -acodec libfaac 它告诉 FFmpeg 为视频轨道使用高级音频编码 (aac) 编码器。
    • -ab 128 它告诉 FFmpeg 以比特率 128 对声音进行编码。
    • -vcodeccopy 它告诉 FFmpeg 使用输入视频的编解码器。这很实用,因为视频无需再次编码,不仅节省了时间,还能生成质量更高的视频。

    Mar

    27

    Flex 内置的 Canvas 、Box、 VBox、HBox 等容器组件当窗格中的内容过大时,滚动条的滑块会为的非常短,鼠标会难以选中操作,通过覆盖 updateDisplayList() 方法来限制滑块的极限值(最小高度与宽度):

    override protected function updateDisplayList(w:Number,h:Number):void {
     super.updateDisplayList(w,h);

     if (verticalScrollBar) {
        //设置 scrollThumb的最小高度。
        verticalScrollBar.scrollThumb.minHeight = 32;
        super.updateDisplayList(w,h);
     }

     if(horizontalScrollBar){
         //注意这里是minHeight,不是minWidth,它是通过垂直滚动条旋转90度实现的
        horizontalScrollBar.scrollThumb.minHeight = 32;
        super.updateDisplayList(w,h);
     }
    }

    More...

    Mar

    27

    Flash Pro CSx 版本的 fl.containers.ScrollPane 组件有一个 scrollDrag,通过这个属性可以设置滚动窗格中内容是否允许被拖动,但 Flex 内置的一些容器组件(比如 Canvas 、Box、 VBox、HBox 等)并不支持这个属性,也没对应的功能,需要自定义类才能实现。下面样例代码让自定义的 Canvas 子类实现窗格中内容可拖动能(其它容器也一样通用):

    package {
        import flash.events.Event;
        import flash.events.MouseEvent;
        import mx.containers.Canvas;
        import mx.core.mx_internal;

        use namespace mx_internal;

        public class PanCanvas extends Canvas {

            private var orgX:Number;
            private var orgY:Number;
            private var orgHScrollPosition:Number;
            private var orgVScrollPosition:Number;
            private var _childrenDoDrag:Boolean = true;

            public function get childrenDoDrag():Boolean {
                return this._childrenDoDrag;
            }

            public function set childrenDoDrag(value:Boolean):void {
                this._childrenDoDrag = value;
            }

            override protected function createChildren():void {
                super.createChildren();
                this.addEventListener(MouseEvent.MOUSE_DOWN, startDragging);
            }

            protected function startDragging(event:MouseEvent):void    {
                if(event.target.parent == this.verticalScrollBar ||    event.target.parent == this.horizontalScrollBar) {
                    return;
                }

                if(_childrenDoDrag || event.target == this) {
                    orgX = event.stageX;
                    orgY = event.stageY;


                    orgHScrollPosition = this.horizontalScrollPosition;
                    orgVScrollPosition = this.verticalScrollPosition;


                    systemManager.addEventListener(MouseEvent.MOUSE_MOVE    , systemManager_mouseMoveHandler, true);
                    systemManager.addEventListener(MouseEvent.MOUSE_UP        , systemManager_mouseUpHandler, true);
                    systemManager.stage.addEventListener(Event.MOUSE_LEAVE    , stage_mouseLeaveHandler);
                }
            }

            private function systemManager_mouseMoveHandler(event:MouseEvent):void {
                //event.stopImmediatePropagation();
                this.verticalScrollPosition = orgVScrollPosition - (event.stageY - orgY);
                this.horizontalScrollPosition = orgHScrollPosition - (event.stageX - orgX);
            }

            private function systemManager_mouseUpHandler(event:MouseEvent):void {
                if (!isNaN(orgX)){
                    stopDragging();
                }
            }

            private function stage_mouseLeaveHandler(event:Event):void {
                if (!isNaN(orgX)){
                    stopDragging();
                }
            }

            protected function stopDragging():void {
                systemManager.removeEventListener(MouseEvent.MOUSE_MOVE        , systemManager_mouseMoveHandler, true);
                systemManager.removeEventListener(MouseEvent.MOUSE_UP        , systemManager_mouseUpHandler, true);
                systemManager.stage.removeEventListener(Event.MOUSE_LEAVE    , stage_mouseLeaveHandler);
                orgX = NaN;
                orgY = NaN;
            }
         }
    }

    Mar

    25

    多么令我向往的世界——《龙猫》

    • 0 Comments
    • Movies, TV and Celebrities

     

    我希望我的宝宝能像小梅那样健康活泼,和我一起住在能够把院子变成森林的大房子里;院子外面有山有水,有农田,还有和蔼的邻居;在院子里面,宝宝能够找到属于自己的龙猫朋友,然后坐上猫巴士去看她的外婆外公。

    More...

    Mar

    25

    我知道,我开始想你了——《大·海》

    • 0 Comments
    • Movies, TV and Celebrities

    有的鱼是永远都关不住的,因为他们属于天空。

                            

    曾经因为这个动画短片了解了什么是 Flash 动画,并因此喜欢上了 Flash 软件,想要努力的学好 Flash 这种技术。如今 4 年过去了,6 年过去了,8 年过去了,将近10 年了(抗日战争也该结束了,孩子都快会打酱油了 - -),可是一直都没能等到《大鱼·海棠》的完整版本,但仍然时不时的会想起它(附上动画短片)。

    Mar

    20

    如果 AS 开发者认为 AS3 中只有通过关键字  new + 类的构造方法 才能创建对象,那就错了。AS3 仍然允许使用 new + 函数名(正式术语为“构造函数”) 创建动态对象,这里的函数名是指函数闭包的名称,可以是局部函数(内嵌函数)、也可以是全局函数,但不能是类的方法。

    通过 new + 函数名 创建对象是 AS1 中面向对象的方法(从 Flash5 & AS 1.1 版本开始的),并通过函数原型对象(prototype 属性引用该对象)来实现传统编程语言中的类继承,只是这种模拟的语法因为与传统业界的编程语言相差太大,并没有得到传统业界程序员的太多认可。

    下面附上一个样例代码:

    package
    {
        import flash.display.Sprite;

        public class AS1 extends Sprite
        {
            public function AS1()
            {
                //定义部份
                function A():void{
                    this.p2 = "p2a";
                }
                function B():void{
                    this.p2 = "p2b";
                }
                A.prototype.p1 = "p1";
                A.prototype.fun = function ():void{
                    trace("a_fun");
                }
                //测试部份
                var a:* = new A();//它们都是无类型的,所以用星号*表示,而不是函数名A
                var b:* = new B();

                trace(a,b);//[object Object] [object Object]
                trace(a.p1);//p1
                trace(a.p2);//p2a
                a.fun();//a_fun
                trace(b.p2);//p2b
            }
        }
    }

    事实上函数支持原型链之外, AS3 的类也支持原型链,在原型对象中定义方法,比如常用的 Object 类的 toString() 方法就在原型对象中定义,所以子类不能使用传统编程语言那样可以使用 override 修饰词去覆盖这个超级根类中的方法,子类直接编写属于自己的 toString() 方法,不需要 override 修饰词(如果写上 override 修饰词编译器反而会报错)。

    备注:在类的原型对象中定义方法时,如果是动态类,类似 Object 类这样可以直接使用点语法,但如果是一个静态类,使用点语法并不能通过编译器,因为静态类的属性或方法中并不存在原型对象中定义的内容,只有在运行期才能确定,所以要将点语法改为中括号 [ ] 访问原型对象中定义的内容。

    Mar

    20

    Adobe AIR for iOS 开发时发现这个方法 System.setClipboard(string:String) 无效,剪贴板中的内容并不会因为这个方法而产生任何改变。但换成以下方法就可以: 

    Clipboard.generalClipboard.clear();
    Clipboard.generalClipboard.setData(ClipboardFormats.TEXT_FORMAT, string:String);

    我没有在安卓中测试,如果在 Adobe AIR for Android 的项目中 System.setClipboard(string:String)  也无效的话,换成上面这个吧。

    More...

    Mar

    20

    动态执行 ActionScript3

    • 0 Comments
    • Flash Platform

    通过 D.eval-1.1.swc 库文件(D.eval-1.1.rar 压缩包中带 API 手册)可以动态执行 AS3 代码,以下为演示代码:

    //入口程序文件
    package
    {
        import flash.display.Sprite;
        import flash.utils.getQualifiedClassName;
        import r1.deval.D;

        public class Test extends Sprite
        {
            public function Test()
            {
                createObj(T,[1,2,3]);
            }
            private function createObj(pClass:Class, pArgs:Array):*{
                D.importClass(pClass);
                var fullQName:String = getQualifiedClassName(pClass);
                var qNameSplit:Array = fullQName.split("::");
                var className:String = qNameSplit[1];
                fullQName = qNameSplit.join(".");
                var args:Array =[];
                for (var i:int = 0; i < pArgs.length; i++) {
                    switch(pArgs[i].constructor) {
                        case String:
                            args[i] = "\"" + pArgs[i] + "\"";
                            break;
                        default:
                            args[i] = pArgs[i];
                            break;
                        //throw new Error("Unhandled type, please add it: " + pArgs[a].constructor);
                    }
                }
                return D.eval("import " + fullQName +" ;\n" + "return new " + fullQName + " (" + args.join(",") + ");");
            }
        }
    }

    下面是一个被测试的T类型

    package 
    {
        public class T
        {
            public function T(a:int,b:int,c:int)
            {
                trace(a,b,c);
            }
        }
    }

    最终它的执行结果输出了:1 2 3,这是非常神奇的事情。 事实上这个库能做很多动态执行 AS3 的事情(比 AS 1.1 / 2中的 eval 函数要强大的多,从它的 API 手册中就可以看出很强大)。比如通过字符串动态执行函数、方法、生成对象等等。但在实际测试中发现它其实也存在一些 Bug,只能够做一些简单的工作,比如将上面的演示代码中 T 在匿名包中可以正常执行,但如果将 T 放在一个有名包中,例如 com.zinewow.test.T 类,那么它就会产一个运行时异常:Runtime Error: msg.rt.no.class。

    个人并不喜欢这种动态执行 AS 的功能,所以在 AS3 中去掉类似 eval 这样的函数也从来没觉的什么不妥。因为这种动态执行代码的情况下,无法在编译期发现错误,总是将错误推迟到运行时。类似的Function 类 apply() 方法,总觉的将错误检测放在运行时检测不是良好的编程习惯,错误应该在编译期迟早可能发现,已经习惯于类似 Python、Javascript  这些动态脚本的开发者可能更喜欢这种自由的方式吧。

    Mar

    17

    SWF 转视频方法 / 教程

    • 0 Comments
    • Miscellaneous

    为什么 SWF 转视频文件的软件这么少

    SWF 文件在播放时虽然它也有声音和画面,但严格意义上讲,它并不是视频文件,而是一种应用程序。因为它的声音和画面并不像普通的视频文件那样在输出时被渲染生成好的静态画面,它在输出的时画面、声音、资源、代码等等都是分离的,最终是在 Flash 播放器(包括控件和插件)正式播放 SWF 文件时被计算生成看到最终的画面和听到的声音。

    所以越是复杂的 SWF 文件被转换成为视频文件的成功率越低:比如一个复杂的网页游戏 SWF 文件,包含大量的 AS 代码,以及与外部 JS 交互的代码,以及与后台服务器程序通信才能生成的画面和声音等等,像这种 SWF 文件基本上是没有转换成为视频文件的可能性(当然除了屏幕录像类软件将整个屏幕画面录制下来之外,但屏幕录像类软件很容易丢失帧画面,它们按照自己的帧频进行录制,并不是按着 Flash 渲染的帧频进行录制)。

    当然大多数情况下,我们只是去转换一些非常简单的 SWF 文件成为视频文件,比如说不含任何代码,或只含少量代码(比如 play、stop 这样的代码)的纯时间轴动画的 SWF 文件,这样的文件转换成为视频的成功率和可能性都会较高。

    但很可惜的是,既便只是想转换一个很简单的纯动画 SWF 成为普通的 AVI、MP4、FLV、VOB、MPG、WMV、ASF、RMVB、TS 等视频格式,网络上也是找不出一款真正好用的 SWF 转视频类的软件。不要相信网络上那些流传的什么ffmpeg、格式工厂、万能转换器、视频转换大师、视频转换王、窝狸、绘声绘影等等软件,因为这类软件它们都是针对已经渲染好的静态画面和声音进行再次编解码处理的。正如前面所介绍的,SWF 的画面和声音它并不是已经渲染好的静态存在,它们只有在 Flash 播放器中运行时才会被确定下来(被动态的渲染输出画面)。既便是 Flash 开发工具在发布 SWF 文件时,让 SWF 不包含任何代码,所有可视素材都被放至在舞台上,它们仍然是动态存在的,并不是渲染好的静态画面,因为 SWF 是一种允许被动态加载和运行的,即一个 SWF 文件完全可以加载另一个 SWF 文件,并控制另一个 SWF 文件中的动画和声音,所以不是已经被渲染生成的静态画面和声音。

    所以像上面那些越是声称自己能支持的格式越多,编解码器越多,就越是不行。如果在百度或谷歌上看到有人在推荐这样“万能型”的软件,就不用去尝试了。因为它们的万能型是针对“视频”文件的,并不是针对“应用”文件的(当然这些软件官方网站并没有声称自己行,只是不了解 Flash 文件的用户的猜测)。

    为什么网络上没有真正好用的 SWF 转视频软件

    那有没有纯粹的将动态的 SWF 渲染成为静态画面的软件呢?答案是肯定的。但事实上这些软件它们都不会好用,有些转换出来的文件只有画面,没有声音;有些转换出来是只有声音没有画面;或者有些转换出来的画面质量非常差;有些甚至根本无法转换等等。特别是一些国内的软件,更是以"骗"为主,让用户花费十几元或几十元购买一个注册码,然后是无法转换的。 原因就在于 SWF 是一种应用格式,它并不是真正的视频文件,是应用格式就意味着会遇到各种不可能遇见的情况,比如非法代码、主时间线只有一帧、影片剪辑嵌套、动态的生成的显示对象等等等。

    所以,像这类软件如果没有试用版本,或试用版本不能够转换到 50% 的长度,最好就不要购买。因为软件属于数字产品,它不同于实物产品,在软件的试用期或试用版中就表示了用户确认了软件的功能,购买之后是无法退货的。至少到现在为止,我和我的同事没有发现任何一款国产软件能真正实现完美转换的,转换出来的情况大多如上一段所述的那样糟糕。

    那是什么原因导致没有人或没有公司去开发真正好用的 SWF 转视频软件?原因很简单:开发一个专业性的软件成本是非常大的(一旦开发就意味着后期的技术支持和软件的长期维护),而使用转换类工具的大多只是个人,在国内一般个人软件消费能力往往非常有限,十几元或几十元;另一方面这种软件需求量很小,所以也无法通过广告收益。所以开发这类软件的往往是个人或小型工作室,没有大型公司参与(Adobe 官方也未参与)。

    另一方面,公司性质或商业项目,专业的视频文件或视频素材大多采用专业的软件来生成,如 Adobe Premiere、Adobe Effects、绘声绘影、3DMAX、MAYA 等等,而不会采用 Flash  创建素材或影片再转换得到。所以想要通过 SWF 转换得到高质量的 AVI、MP4 等视频文件就需要一定的技巧和方法。下面提供两种:

    高质量视 频文件生成(难度较大)

    Flash 开发者使用位图编程逐帧 draw() 舞台,然后使用屏幕无损的 png 编码输出每一个静态画面成为序列图,并利用 SWF 反编译软件提取音频文件,最后将所有序列图和音频文件导入到专业的视频软件(如 Adobe 公司的 AE)中进行合并渲染输出。当然这些专业性的软件本身也是非常大的,每个软件好几 G 的大小(既便是压缩版的也有1-2G)。而且像 Flash 和 AE 这些专业性的软件,普通用户如果没有相应的知识,就无法操作了。

    普通质量文件生成(难度适中低)

    可以使用 Free SWF Converter、iWisoft Flash SWF to Video Converter 以及 Moyea SWF to Video Pro 等等(之所以推荐国外的软件是因为国内同类型的软件基本比较坑爹型,没试出一个好的来)。

    重点推荐:Moyea SWF to Video Converter Pro,它的优点是文件容量比较小(只有几十M),生成的画面质量很不错,支持多种格式和多种编解码方式,并且它有一个非常大的优点就是支持包含代码的 SWF 文件的渲染输出成视频文件,因为它是通过捕获 SWF 运行时的舞台画面得到最终静态画面的,所以既便包复杂的 AS 代码和运行时需要加载外部的资源文件也没有关系。但它有一个缺点如前面所述的,虽然它包含了声音选项,但实际上它最终渲染输出的文件是没有声音的(前面提到的其它两个软件也一样,Free SWF Converter、iWisoft Flash SWF to Video Converter 录制以后也是没有声音的,是通病)。可以通过一个 SWF 反编译软件(硕思闪客精灵)提取音频文件,然后与视频合并。

    音频与视频合并时意味着需要对画面和声音文件重新进行编码,如果挑选的合并软件不恰当,既便 Moyea SWF to Video Converter Pro 输出了较好质量的视频文件,在重新编码后也会变的较差,所以本人也是尝试了很多种合并软件,最后发现国产免费软件“QQ影音”的工具菜单(或工具按扭)中就有这个视频与音频合并的功能,生成的画质也是非常好。