AS3 Multithreading Quick Start (ii): Image processing [translate]

Source: Internet
Author: User

Original link: http://esdot.ca/site/2012/intro-to-as3-workers-part-2-image-processing

In the first part of the AS3 multi-threaded QuickStart Tutorial series, we studied the fundamentals of AS3 Worker, including a variety of communication methods, and also showed a simple example: Hello world worker.

In this article, I will go a step further and show you how to use multithreading to do some useful functions, than like processing! In this example, I'm going to apply sharpening filters to a large bitmap while keeping the main UI thread in the 30fps render frame rate.

Demo: Single thread version

You can simply look at what we are going to do below. This is a version that does not use workers, and you can see that the slider is completely locked during bitmap processing and cannot be moved.

Note: If you do not see this SWF program, check if you have downloaded the Flash Player11.4. If you are using Google Chrome, do not forget to disable the old version of the plugin.

Demo: Multi-threaded version

The following is the same demo program, but the worker is used. You can see that its UI rendering is maintained smoothly at 30fps.

Note: If you do not see this SWF program, check if you have downloaded Fash Player11.4. If you are using Google Chrome, do not forget to disable the old version of the plugin.

Code

Before you actually start writing code, it's important to be proactive. Especially when dealing with multi-threading, we do need to create an efficient system that dispatches data between workers. Otherwise, your main thread will get bogged down by the huge overhead of serializing and deserializing the data.

After a little thought, I decided to put this into this program:

1.bitmapData is shared with the worker through a ByteArray object that shareable to true.
2. We use the Bitmapdata.setpixels () and Bitmapdata.copypixelstobytearray () methods to convert back and forth between BitmapData and ByteArray.
3. The main thread issues the "sharpen" command to the worker, and the worker thread returns the "Sharpen_compelete" command when it finishes.
4.worker threads will use a 500ms timer to detect if a sharpening operation needs to be restarted. Prevents over-running sharpening operations.

Document class Code

The first is the class structure, which we'll use in the same way as in the previous tutorial: Using Loaderinof.bytes. This constructor is run two times, and the second time you run the worker, it creates an instance of the Sharpenworker class that will handle all communication with the main thread.

?
12345678910111213 public class ImageWorkerExample extends Sprite{public function ImageWorkerExample(){    //主线程    if(Worker.current.isPrimordial){        initUi();        initWorker();    }     //如果不是主线程,就是worker    else {        sharpenWorker = new SharpenWorker();    }}

Before we look at the Sharpenworker class, we'll go ahead and read the main class.

The Initui () method simply creates a slider, an image, and adds them to the stage. There is no need to pay attention to it here.

The next method is Initworker (), and you can look at the comments within the code.

?
1234567891011121314151617181920212223242526272829 protected function initWorker():void {    //从主swf里创建worker     worker = WorkerDomain.current.createWorker(loaderInfo.bytes);    //创建到worker的MessageChannel通信对象    mainToBack = Worker.current.createMessageChannel(worker);    //创建来自worker的MessageChannel通信对象并添加监听.    backToMain = worker.createMessageChannel(Worker.current);    backToMain.addEventListener(Event.CHANNEL_MESSAGE, onBackToMain, false, 0, true);    //现在我们有两个通信对象,把它们作为共享属性注入到worker线程    //这样,worker线程就能在另一边获取它们    worker.setSharedProperty("backToMain", backToMain);    worker.setSharedProperty("mainToBack", mainToBack);    //给worker传递初始化图像宽高尺寸    worker.setSharedProperty("imageWidth", origImage.width);    worker.setSharedProperty("imageHeight", origImage.height);    //转换位图数据并存储到共享的byteArray对象里,与worker线程共享。    imageBytes = new ByteArray();    imageBytes.shareable = true;    origImage.copyPixelsToByteArray(origImage.rect, imageBytes);    worker.setSharedProperty("imageBytes", imageBytes);    //最后,启动worker线程.    worker.start();}

In the above code, we have done these things:

1. Create a worker using our own loaderinfo.bytes.
2. The Messagechannel object is created so that the main thread and the worker thread can communicate with each other.
3. Copy the bitmap data inside the shared ByteArray object.
4. Share the bitmap data with the worker thread.
5. Start the worker thread.

The next step is to notify the worker in the main class to sharpen the bitmap and respond when the task is completed.

First, we'll add the Change event handler for the slider:

?
12345 protectedfunction onSliderChanged(value:Number):void{    //给我们的worker线程发送锐化命令.    mainToBack.send("SHARPEN");    mainToBack.send(value);}

We then add a response function when the worker finishes the task.

?
1234567 protected function onBackToMain(event:Event):void {    var msg:String = backToMain.receive();    if(msg == "SHARPEN_COMPLETE"){        imageBytes.position = 0;        image.bitmapData.setPixels(image.bitmapData.rect, imageBytes);    }}

The above is finished the main class code!

Worker Code

The structure of the worker class is straightforward and straightforward:

?
123456789101112131415161718192021222324252627 public class SharpenWorker extends Sprite{ public function SharpenWorker(){    //获取当前worker线程的引用(自身)    var worker:Worker = Worker.current;    //监听mainToBack的SHARPEN事件    mainToBack = worker.getSharedProperty("mainToBack");    mainToBack.addEventListener(Event.CHANNEL_MESSAGE, onMainToBack);    //使用backToMain抛出SHARPEN_COMPLETE命令    backToMain = worker.getSharedProperty("backToMain");    //从共享属性缓存池里获取位图数据。    imageBytes = worker.getSharedProperty("imageBytes");    var w:int = worker.getSharedProperty("imageWidth");    var h:int = worker.getSharedProperty("imageHeight");    imageBytes.position = 0;    imageData = new BitmapData(w, h, false, 0x0);    backToMain.send(imageBytes.length);    imageData.setPixels(imageData.rect, imageBytes);    //创建计时器间隔检测锐化值是否已经改变了    timer = new Timer(500);    timer.addEventListener(TimerEvent.TIMER, onTimer, false, 0, true);    timer.start();}

Here we have done these things:

1. Hold the Messagechanel object reference for the main thread share.
2. Initialize the BitmapData with shared ByteArray object data.
3. Store a reference to the ByteArray object internally, so that we can write data to it from now on.
4. Create a timer to detect whether you need to sharpen again.

Next, we need to respond to sharpen requests. This is handled in the Maintoback listener function:

?
1234567891011 protected function onMainToBack(event:Event):void {    if(mainToBack.messageAvailable){        //获取消息类型        var msg:* = mainToBack.receive();        //锐化        if(msg == "SHARPEN"){            targetSharpen = mainToBack.receive();        }    }}

Note that here we are actually not doing anything except storing the sharpening values. It would be a waste of performance if we applied the sharpening operation immediately every time we requested it. Sharpening takes more than 500ms of time to complete, but the main thread sends the sharpening command at 33ms intervals. So obviously, if we respond to each request it will cause a huge blockage. Eventually your worker thread will crash.

Instead, we apply the sharpen filter in the Timer event handler in interval 500ms:

?
123456789101112 protected function onTimer(event:TimerEvent):void {    if(targetSharpen == currentSharpen){ return; } //直到锐化值改变才启动锐化    currentSharpen = targetSharpen;    //锐化位图并复制它到byteArray对象里    var data:BitmapData = ImageUtils.SharpenImage(imageData, currentSharpen);    imageBytes.length = 0;    data.copyPixelsToByteArray(data.rect, imageBytes);     //通知主线程锐化操作已经完成    backToMain.send("SHARPEN_COMPLETE");}

That's all the code. The main thread will send the sharpen command with the sharpening value, and after the worker thread gets to it, update the shared ByteArray object data and back to the Sharpen_complete command. Once the Sharpen_complete command is received, the main thread updates the bitmap display object with the shared ByteArray data.

Note: If you are interested in sharpening the operation itself, this excellent filter comes from gskinner.com.

You can download it here to complete the test Code project:

Imageworkerexample (includes code examples with no multithreading)

Multi-threaded Use happy!

From: http://blog.domlib.com/articles/326.html

AS3 Multithreading Quick Start (ii): Image processing [translate]

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.