
高级技术文档撰写工程师
Adobe
图 1 所示的 PhotoUpload 范例应用程序演示 Adobe AIR 的以下文件处理功能:

图 1。通过本范例应用程序可以上载 JPEG 文件。
注意: 本范例应用程序按原样提供, 用于教学目的。
若要充分利用本篇文章, 您需要以下软件和文件:
本范例应用程序包括以下文件:
本应用程序要求安装网络摄像头, 且必须有权访问支持 PHP 的 Web 服务器。
应具备构建 HTML 应用程序的一般经验。有关使用此快速入门指南的详细信息, 请参阅用 HTML 构建快速入门范例应用程序。
通过本范例应用程序, 可以从网络摄像头捕获图像, 并将所捕获的图像 (存储为 JPEG 文件) 上载至 Web 服务器。
Photo Uploader 使用 SWF 文件的 JPGEncoder 类将数据转换为 JPEG 格式。JPGEncoder 类发布在 ActionScript 3.0 Corelib 项目 (位于 http://code.google.com/p/as3corelib) 中。
运行应用程序 (PhotoUploadHTML.air) 之前, 在支持 PHP 的 Web 服务器的 http://localhost/PhotoSyncUpload/ 文件夹中安装 index.php 文件 (随 PHP 目录中的源文件一起提供)。此外, 请确保在计算机上安装了网络摄像头。
测试应用程序:
有关使用 AIR 类的详细信息, 请参阅《为 HTML 开发人员提供的 Adobe AIR 语言参考》*。
Uploader.js 文件中的 appInit() 方法使用 ActionScript 3.0 文档中所记载的两个类: Camera 类和 Video 类。通过调用 Camera 类的 getCamera() 方法, 向 camera 对象 (Camera 类的实例) 分配用户计算机上的一台网络摄像头。如果没有摄像头, 应用程序将通过调用 alert() 函数通知用户。video 对象 (Video 类的实例) 是为显示摄像头所捕获图像而分配的 ActionScript 3.0 显示对象。
camera = window.runtime.flash.media.Camera.getCamera();
if (camera)
{
video = new window.runtime.flash.media.Video();
video.attachCamera(camera);
camera.addEventListener(air.ActivityEvent.ACTIVITY, setSize);
}
else
{
alert("No cameras are available.");
}
setSize() 函数设置视频的高度和宽度, 然后调用 shoot() 函数:
function setSize()
{
video.width = camera.width * 2;
video.height = camera.height * 2;
shoot(false);
}
shoot() 函数调用 flasher() 函数, 后者模拟照相机的闪光灯, 方法是快速呈现一个不透明的白色 NativeWindow 来填充屏幕:
function shoot(flash)
{
if (flash)
{
flasher();
}
bmd = new window.runtime.flash.display.BitmapData(video.width, video.height);
bmd.draw(video);
saveTemp();
}
function flasher()
{
var windowInitOpts = new air.NativeWindowInitOptions();
windowInitOpts.systemChrome = air.NativeWindowSystemChrome.NONE;
windowInitOpts.type = air.NativeWindowType.LIGHTWEIGHT;
var flashCube = new air.NativeWindow(windowInitOpts);
flashCube.x = 0;
flashCube.y = 0;
flashCube.width = air.Capabilities.screenResolutionX;
flashCube.height = air.Capabilities.screenResolutionY;
flashCube.visible = true;
setTimeout(closeFlash, 100, flashCube);
}
function closeFlash(flashCube) {
flashCube.close();
}
应用程序在初始化过程中 (在 appInit() 方法中) 首次调用 shoot 方法时, 将该方法的 flash 参数设置为 false。
然后, shoot() 方法捕获 video 对象中的图像, 并将其保存至 BitmapData 对象 bmd。有关 flash.display.BitmapData 类的介绍, 请参见 ActionScript 3.0 文档。
bmd = new window.runtime.flash.display.BitmapData(video.width, video.height); bmd.draw(video);
应用程序初始化时以及用户单击 Preview 按钮时, saveTemp() 方法将图像保存至 JPEG 文件, 随后将其加载至 img 图像中。
应用程序必须将 bmd 对象中包含的 BitmapData 数据转换为 JPEG 格式。corelib 项目 (位于 http://code.google.com/p/as3corelib) 中发布的 JPGEncoder ActionScript 3.0 类即可实现此功能。随 swf 目录中的源文件一起提供的 JPGEncoderLib.swf 文件包含该 JPGEncoder 类, 而本 HTML 应用程序通过使用 (index.html 文件中的) 以下脚本标签加载 SWF 文件, 使该 SWF 文件中的类可供 JavaScript 代码使用:
<script src="swf/JPGEncoderLib.swf" type="application/x-shockwave-flash"></script>
saveTemp() 函数将 JPEG 数据保存至 (通过调用 air.File.createTempFile() 创建的) 某个临时文件。通过创建 FileStream 对象并调用该对象的 writeBytes() 方法, 将数据保存至文件。然后, 将该临时文件加载至文档中的 img 图像中。通过调用 JPGEncoder 对象的 encode() 方法, 将图像数据转换为包含按 JPEG 编码的数据的 ByteArray 对象:
function saveTemp()
{
tempFile = air.File.createTempFile();
temps.push(tempFile);
saveJPEG(tempFile);
img.src = "";
img = window.document.getElementById("img");
img.src = tempFile.url;
img.width = 320;
img.height = 240;
}
function saveJPEG(file) {
stream = new air.FileStream();
stream.open(file, air.FileMode.WRITE);
var data = getJPEGData(bmd);
stream.writeBytes(data, 0, data.length);
stream.close();
return file;
}
function getJPEGData(bmd) {
var jpegEncoder = new window.runtime.com.adobe.images.JPGEncoder();
return jpegEncoder.encode(bmd);
}
用户单击 Save 按钮时, save() 方法将图像保存至应用程序资源目录的图像子目录中的 JPEG 文件。文件按 Date 对象的 time 属性所提供的时间戳来命名:
function save()
{
var timestamp = new Date().getTime().toString();
var path = "images/" + timestamp + ".jpg";
file = air.File.applicationStorageDirectory.resolvePath(path);
saveJPEG(file);
}
Uploader.as 文件包含用于将文件上载至 Web 服务器的代码。已保存文件的列表存储在 files 数组 (File 对象数组) 中。upload() 方法检查应用程序存储目录的图像子目录中文件的列表:
function upload()
{
totalSize = 0;
files = new Array();
var dir = air.File.applicationStorageDirectory.resolvePath("images");
var allNodes = dir.getDirectoryListing();
for (var i = 0; i < allNodes.length; i++)
{
file = allNodes[i];
if (!file.isDirectory)
{
files.push(file);
totalSize += file.size;
}
}
url = UPLOAD_URL
uploadedSoFar = 0;
uploadNext();
}
uploadNext() 函数从 files 数组中提取一个 File 对象, 并调用 uploadFile() 函数, 该函数将上载文件:
function uploadNext()
{
if (files.length > 0)
{
currentFile = files.pop();
uploadFile(currentFile);
}
}
function uploadFile(file)
{
var urlRequest = new air.URLRequest(url);
urlRequest.method = air.URLRequestMethod.POST;
file.addEventListener(air.ProgressEvent.PROGRESS, uploadProgress);
file.addEventListener(air.Event.COMPLETE, uploadComplete);
file.addEventListener(air.SecurityErrorEvent.SECURITY_ERROR, uploadError);
file.addEventListener(air.HTTPStatusEvent.HTTP_STATUS, uploadError);
file.addEventListener(air.IOErrorEvent.IO_ERROR, uploadError);
file.upload(urlRequest, "uploadfile");
}
uploadFile() 函数为所上载的 File 对象设置若干事件侦听器:
function uploadProgress(event)
{
var uploadedAmt = uploadedSoFar + event.bytesLoaded;
event.bytesLoaded = uploadedAmt;
event.bytesTotal = totalSize;
air.trace("Progress", event.bytesLoaded, event.bytesTotal);
}
function uploadComplete(event)
{
uploadedSoFar += currentFile.size;
var newLocation = currentFile.parent.resolvePath("uploaded/" + currentFile.name);
uploadNext();
}
function uploadError(event)
{
var errorStr = event.toString();
air.trace("Error uploading: " + currentFile.nativePath + "\n Message: " + errorStr);
}
请注意, 上载文件时调用的事件处理函数 (uploadComplete() 函数) 将调用 uploadNext() 函数以上载下一个文件 (如果有)。
在 Web 服务器上张贴的 PHP 页面将字符串视为提示, 以便将以 POST 数据提供的文件接受为要上载 (并保存在 Web 服务器上的“uploaded”子目录中) 的文件。
appInit() 函数为 exiting 事件设置事件侦听器, 应用程序退出时 NativeApplication 对象将调度该事件:
air.NativeApplication.nativeApplication.addEventListener(air.Event.EXITING, appExiting);
NativeApplication 对象在用户关闭主窗口时调度 exiting 事件。appExiting() 函数处理 exiting 事件, 在应用程序真正关闭之前保存会话过程中所使用的临时文件的数组:
function appExiting(event)
{
for (i = 0; i < temps.length; i++)
{
tempFile = temps[i];
tempFile.deleteFile();
}
}