红帽白皮书新鲜出炉!点击获取,让你的云战略更胜一筹! 了解详情
写点什么

从 CameraRoll 和 CameraUI 上传图像

  • 2011-09-02
  • 本文字数:3861 字

    阅读完需:约 13 分钟

目录

需求

预备知识

使用 Flash Builder、Flash Professional 或建议的其他工具构建 AIR 应用程序的一般经验。

用户水平

中级

需要的产品

示例文件

本文探讨如何通过 CameraRoll 和 CameraUI 类将获得的图像上传到服务器。

CameraRoll 类可用于打开一个图像浏览器,以便用户可从设备媒体库选择照片。CameraUI 类可用于启动设备照相机应用程序,以便用户可拍摄照片或录制视频。在两种情况下,CameraRoll 和 CameraUI 对象都通过一个包含媒体承诺的事件来返回媒体。

可用于访问媒体承诺中的数据的选项在各个平台中不尽相同。例如,在 Android 上,媒体承诺包括一个引用源图像文件 file 属性,但在 iOS 上,此属性始终为空——源文件不可访问。本文中描述的技术适用于所有平台。

获取媒体承诺

第一步是从CameraRoll 或CameraUI 对象请求图像。在两种情况下,您都会创建合适的对象,设置一些事件监听器,然后调用请求图像的函数。然后,在用户从设备媒体库选择一张照片或使用照相机拍摄一张新照片之后,运行时在一个包含媒体承诺的事件中返回图像。

CameraRoll

下面的代码示例设置必要的事件监听器来处理可由 CameraRoll 对象分配的事件,然后调用 browseForImage() 方法。当用户选择一张图像时,运行时调用一个名为 imageSelected 的事件处理函数。

复制代码
//declare cameraRoll where it won't go out of scope
var cameraRoll:CameraRoll = new CameraRoll();
if( CameraRoll.supportsBrowseForImage )
{
cameraRoll.addEventListener( MediaEvent.SELECT, imageSelected );
cameraRoll.addEventListener( Event.CANCEL, browseCanceled );
cameraRoll.addEventListener( ErrorEvent.ERROR, mediaError );
cameraRoll.browseForImage();
}
else
{
trace( "Image browsing is not supported on this device.");
}

CameraUI

从 CameraUI 对象请求图像的代码非常类似:

复制代码
private var cameraUI:CameraUI = new CameraUI();
if( CameraUI.isSupported )
{
trace( "Initializing..." );
cameraUI.addEventListener( MediaEvent.COMPLETE, imageSelected );
cameraUI.addEventListener( Event.CANCEL, browseCanceled );
cameraUI.addEventListener( ErrorEvent.ERROR, mediaError );
cameraUI.launch( MediaType.IMAGE );
}
else
{
trace( "CameraUI is not supported.");
}

要注意的一点区别是,CameraRoll 分派一个类型为 MediaEvent.SELECT 的事件,而 CameraUI 类分派一个类型为 MediaEvent.COMPLETE 的事件。

获得原始图像数据

您可以从媒体承诺以字节数组的形式获取原始图像数据。但媒体承诺对象可以以一些不同方式提供自己的数据。所以,强健的跨平台解决方案的创建需要费一定的工夫。在 Android 上,CameraRoll 和 CameraUI 分派的媒体承诺包括一个引用图像文件的 File 对象。但是,File 对象在 iOS 上不可用。如果您的代码直接打开文件,它将仅适用于 Android。

如果您只希望显示图像,可以始终使用 Loader.loadMediaPromise() 方法。此方法加载图像并将它解码为一个显示对象。但要上传图像,您需要一个包含图像数据的 File 对象或 ByteArray 对象,而不是 Flash 显示对象。您可以使用 MediaPromise 对象的 file 属性(如果可用),但当 file 属性不可用时,可以通过读取媒体承诺数据源来访问图像数据。

媒体承诺对象提供了对可能同步或异步的数据源的访问。在同步情形下,您可以打开数据源并立即读取数据。但在异步情形下,在数据可用之前必须等待事件进展或完成事件。

下面的代码示例检查媒体承诺数据是同步的还是异步的(使用 isAsync 属性)。在异步情形下,该示例添加一个事件监听器。因为您不知道实际数据源的对象类型是什么,所以必须使用“as”运算符将它转换为合适的接口。将对象转换为 IdataInput 接口,以从数据源读取数据。将他转换为 IeventDispatcher 接口,可以访问异步数据源的 addEventListener() 方法。

复制代码
private var dataSource:IDataInput;
private function imageSelected( event:MediaEvent ):void
{
trace( "Media selected..." );
var imagePromise:MediaPromise = event.data;
dataSource = imagePromise.open();
if( imagePromise.isAsync )
{
trace( "Asynchronous media promise." );
var eventSource:IEventDispatcher = dataSource as IEventDispatcher;
eventSource.addEventListener( Event.COMPLETE, onMediaLoaded );
}
else
{
trace( "Synchronous media promise." );
readMediaData();
}
}
private function onMediaLoaded( event:Event ):void
{
trace("Media load complete");
readMediaData();
}
private function readMediaData():void
{
//do something with the data
}

上传图像

上传图像的最简单方式是使用FileReference.upload()。是的,我知道我刚才告诉您不要依靠文件的存在与否。但是,如果没有从媒体承诺直接获得文件,可以自行创建一个临时文件。使用FileReference.upload() 的另一个优势是,它执行一种多部分表单样式上传。许多服务器端上传脚本要求这种类型的上传,因为允许用户上传文件的HTML 表单常常使用它。

另一个选项是使用URLLoader 类直接上传字节数组。以原始字节数组形式执行上传也很简单。但是,如果您的服务器脚本希望采用多部分表单上传,您将必须编写代码来创建对恰当格式的请求。除了FileReference.upload(),没有任何ActionScript API 可为您提供直接帮助。您可以使用一些第三方库,比如Eugene Zatepyakin 的开源 MultipartURLLoader 类。

FileReference.upload()

下面的示例演示了如何创建和上传临时文件:

复制代码
private function readMediaData():void
{
var imageBytes:ByteArray = new ByteArray();
dataSource.readBytes( imageBytes );
tempDir = File.createTempDirectory();
var now:Date = new Date();
var filename:String = "IMG" + now.fullYear + now.month + now.day + now.hours + now.minutes + now.seconds + ".jpg";
var temp:File = tempDir.resolvePath( filename );
var stream:FileStream = new FileStream();
stream.open( temp, FileMode.WRITE );
stream.writeBytes( imageBytes );
stream.close();
temp.addEventListener( Event.COMPLETE, uploadComplete );
temp.addEventListener( IOErrorEvent.IO_ERROR, ioError );
try
{
temp.upload( new URLRequest( serverURL ) );
}
catch( e:Error )
{
trace( e );
removeTempDir();
cameraUI.launch( MediaType.IMAGE )
}
}
private function removeTempDir():void
{
tempDir.deleteDirectory( true );
tempDir = null;
}

您可以使用 ActionScript 3 开发人员指南中提供的这个 PHP 脚本示例测试上传功能。(请记住增大脚本中定义的最大文件大小,以容纳您的设备照相机生成的图像。)

URLLoader

如果能够控制接受图像上传的服务器端脚本,可以直接上传图像字节,而无需创建临时文件。在 iOS 上,这可以节省一定的内存,因为内存中的图像数据副本可能比其他时候更少。但与任何优化一样,您应该评估是否值得为预期的收益付出努力。

下面的函数以字节数组形式上传图像:

复制代码
public function upload( data:ByteArray, destination:String, fileName:String = null ):void
{
if( fileName == null ) //Make a name with correct file type
{
var type:String = sniffFileType( buffer );
var now:Date = new Date();
fileName = "IMG" + now.fullYear + now.month +now.day +
now.hours + now.minutes + now.seconds + ".jpg";
}
loader = new URLLoader();
loader.dataFormat= URLLoaderDataFormat.BINARY;
var urlString:String = destination + "?file=" + fileName;
var request:URLRequest = new URLRequest( urlString );
request.data = data;
request.method = URLRequestMethod.POST;
request.contentType = "application/octet-stream";
loader.addEventListener( Event.COMPLETE, onUploadComplete );
loader.addEventListener(IOErrorEvent.IO_ERROR, onUploadError );
loader.load(request);
}

您可以在示例文件中的 Uploader 类中找到此函数的代码。您可以使用以下简单的 PHP 脚本测试该函数:

复制代码
<?php
if ( isset ( $GLOBALS["HTTP_RAW_POST_DATA"] )) {
$flux = $GLOBALS["HTTP_RAW_POST_DATA"];
$fp = fopen('.images/' . $_GET['file'], 'wb');
fwrite($fp, $flux);
fclose($fp);
}
?>

延伸阅读

本文介绍了如何从媒体承诺对象获取图像数据,以及两种将该数据上传到服务器的轻松方式。广泛来讲,您的上传函数将需要添加标头和参数,才符合特定的照片服务 API。也可以在 ActionScript 3 开发人员指南和 ActionScript 3 参考指南中找到关于 CameraRoll 和 CameraUI 的更多信息:

clip_image002 +clip_image003

此作品依据 Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License 授权。超过本许可的与本作品中包含的代码示例相关的权限可在 Adobe 上找到。

查看原文: Uploading images from CameraRoll and CameraUI

2011-09-02 00:001891

评论

发布
暂无评论
发现更多内容

web前端培训 | 代码如何配置规范并格式化

@零度

前端开发

Yii2文件/图片上传实例

Owen Zhang

php

【直播回顾】Hello HarmonyOS进阶课程第四课——ArkUI动画开发

HarmonyOS开发者

HarmonyOS

数据指标体系如何搭建才最有效,从0到1带你快速入门丨02期直播回顾

袋鼠云数栈

【LeetCode】房屋偷盗Java题解

Albert

LeetCode 5月月更

做SAP freelancer 的几个注意事项

SAP虾客

SAP freelancer 黑名单 业界名声

浅谈SAP顾问未来十年在中国的发展前景

SAP虾客

SAP顾问 技术专家 行业专家

行业分析| 智能安防的发展

anyRTC开发者

人工智能 AI 音视频 安防 快对讲

消灭非稳态噪音的利器 - AI 降噪

ZEGO即构

RTC AI降噪 网络降噪

【高并发】优化加锁方式时竟然死锁了!!

冰河

并发编程 多线程 高并发 协程 异步编程

大咖说|Kubernetes自动伸缩实现方式深度讲解

云智慧AIOps社区

云计算 微服务 云原生 #Kubernetes#

什么是知识管理?知识管理的方法?

小炮

原生即时通讯APP四合一成品聊天软件源码搭建个性化需求定制开发

WorkPlus

50万条数据 深挖四川数字经济“发展密码”:四川数字经济发展分析

易观分析

数字经济

大数据培训 | Doris数据导入与导出

@零度

Doris 大数据开发

王者荣耀商城异地多活架构设计

哈喽

「架构实战营」

等保测评师是做什么的?工资怎么样?

行云管家

网络安全 IT运维 等保测评 等保测评师

leetcode 34. Find First and Last Position of Element in Sorted Array 在排序数组中查找元素的第一个和最后一个位置(中等)

okokabcd

LeetCode 查找

确保 Kubernetes 安全合规的 6 个最佳实践

Rancher

Kubernetes k8s rancher

建站建设必备的资料是什么?

源字节1号

软件开发

TiDBv6.0与TiDBv5.1.2 TiKV 节点重启后 leader 平衡加速,提升业务恢复速度对比测试

TiDB 社区干货传送门

得物技术Filament Creator材质编辑工具的实现

得物技术

模型 3D模型 3D 渲染 引擎

JavaScript this全解析

源字节1号

软件开发 前端开发 后端开发 小程序开发

【云管理】企业多元化私有云设施管理用什么软件好?

行云管家

云计算 私有云 IT运维 云管理

当前中小企业网络营销缺少的三个方面

源字节1号

前端开发 后端开发 小程序开发 网站开发

5G 时代,我们需要更便捷的RTC技术服务

HIFIVE音加加

RTC 音乐

数仓血缘关系数据的存储与读写

NebulaGraph

图数据库 知识图谱 Nebula Graph

案例成果展 | 灵雀云助力中国人民银行清算总中心构建裸金属容器平台

York

灵雀云 容器 微服务 云原生

一款免费的排队叫号工具,居然有这么多功能,赶紧收藏起来!

天天预约

小程序 SaaS 工具分享 排队

深度学习利器之GPU

AIWeker

人工智能 深度学习 gpu 5月月更

java培训 | Mybatis 中的 PreparedStatement 预编译

@零度

mybatis JAVA开发

从CameraRoll和CameraUI上传图像_语言 & 开发_Joe Ward_InfoQ精选文章