1

我正在制作一个简单的工具,让用户最终将图像保存到磁盘。为此,我使用了FileStream类及其writeBytes()方法。

这工作得很好。当我尝试使用简单的mx:ProgressBar. 我尝试了一些方法,但似乎都没有奏效。

这是 ActionScript 的一段代码:

private function save(file:File, image:MyImageClass):void {
    var data:BitmapData = new BitmapData(width, height, true, 0x000000);
    image.draw(data, _cols);
    var bytes:ByteArray = new PNGEncoder().encode(data);
    fileStream = new FileStream();
    fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, onProgress);
    fileStream.addEventListener(Event.CLOSE, onClose);
    try {
        fileStream.openAsync(file, FileMode.WRITE);
        fileStream.writeBytes(bytes);
    } catch (e:Error) {
        Alert.show("Error trying to save the image: " + e.message);
    } finally {
        fileStream.close();
    }
}

private function onProgress(event:OutputProgressEvent):void {
    var progressRatio:Number = (1 - (event.bytesPending / event.bytesTotal));
    progressBar.setProgress(progressRatio, 1);
    trace(progressRatio);
    if (event.bytesPending == 0)
        event.target.close();
}

private function onClose(event:Event):void {
    trace("closed");
}

以及进度条的 mxml:

<mx:ProgressBar id="progressBar" mode="manual"/>

执行这个我得到了一个冻结的界面,当文件完全保存时释放,在控制台上我同时得到所有的痕迹。进度条保持在 0%,直到界面解冻并变为 100%。

我知道 Flash 是单线程的,但我认为该FileStream.openAsync()方法应该做一些脏活来让我的接口负责。完成这个简单且(我认为)常见的任务应该不难。

问题是:我做错了什么?

提前致谢

4

3 回答 3

3

保存的文件有多大?

就保存文件而言,您的代码似乎很好。但是,我怀疑实际上需要很长时间才能将文件编码为 PNG 格式。不幸的是,PNGEncoder不会调度任何进度事件。但是您应该查看Lee Burrows 的这个项目,或者考虑使用 Actionscript Workers 在不同的线程中进行编码。

快速证明它的方法:在编码为 PNG 之前/之后添加跟踪语句。大延迟是对应于这个阶段,还是对应于实际的保存?

如果这没有帮助,请指定您的文件有多大,以及您是否获得 0、1 或多个 OUTPUT_PROGRESS 事件。

于 2013-07-04T23:22:06.507 回答
1

我同意 Sunil 的观点,但我想补充一两点。

首先,我建议使用BitmapData类的新方法来编码图像,因为它更快更容易。所以你的代码会变成这样:

var data:BitmapData = new BitmapData(width, height, true, 0x000000);
image.draw(data, _cols);
var bytes:ByteArray = data.encode(data.rect, new PNGEncoderOptions());

您可以像这样跟踪写入文件的进度(尽管我怀疑这不会花费太多时间,就像 Sunil 说的那样):

bytes.position = 0;
while(bytes.bytesAvailable > 0) {
    fileStream.writeByte(bytes.readByte());
    trace("progress:", bytes.position / bytes.length * 100); // multiply by 100 for percentage
}

请注意,这种方法需要一个工作人员,否则进度只会在保存完成后视觉更新。

于 2013-07-05T08:31:06.590 回答
1

苏尼尔是正确的。写文件几乎不需要一点时间。它正在解码阻塞应用程序的字节数组。我实现了以下代码来测试它。

private function save(file:File):void
{
    var bytes:ByteArray = new ByteArray();
    //233348 - very fast (requires 6000 x 10000 bitmap pixels)
    //252790 - very fast (requires 6500 x 10000 bitmap pixels)
    //2488990 - need a whole magnitude more of data in order to show the progress messages
    for (var i:int = 0; i < 2488990; i++)
    {
        bytes.writeByte(1);
    }
    var fileStream:FileStream = new FileStream();
    fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, onProgress);
    fileStream.addEventListener(Event.CLOSE, onClose);
    try {
        fileStream.openAsync(file, FileMode.WRITE);
        fileStream.writeBytes(bytes);
    } catch (e:Error) {
        //Alert.show("Error trying to save the image: " + e.message);
    } finally {
        fileStream.close();
    }
}

您将需要解码任务而不是文件写入任务的进度指示器。Workers 似乎是最好的解决方案,但这取决于您需要定位的运行时版本。

于 2013-07-05T10:02:29.113 回答