写点什么

从 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:002071

评论

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

一名分布式存储工程师的技能树是怎样的?

焱融科技

分布式 存储 分布式存储 分布式文件

STM32标准库开发实战指南

华为云开发者联盟

SMT32处理器 stm32 内核 寄存器

写作感悟之无从下笔

JiangX

写作 28天写作

创业失败启示录|校园微生活(故事篇1)

阿萌

创业 28天写作 创业失败启示录 青城

从标准到开发,解读基于MOF的应用模型管理

华为云开发者联盟

模型 ROMA 应用模型 mof

SpringCloud 微服务实现数据权限控制

Barry的异想世界

SpringCloud SpringBoot 2 权限认证 数据权限

回顾2020年那些“领域第一本”,每一本都强烈推荐!

博文视点Broadview

五分钟快速掌握Maven的核心概念

田维常

maven

没想到,学习带给我最宝贵的东西是底气

Sandy

springboot多模块配置问题

原来不悔

springboot Spring Frame

Java 程序经验小结:剖析方法重载

后台技术汇

28天写作

【吐血整理】超全golang面试题合集+golang学习指南+golang知识图谱+成长路线 一份涵盖大部分golang程序员所需要掌握的核心知识

小白debug

面试 新手指南 编程之路 职业成长 Go 语言

微软开源WebUI自动化测试神器Playwright​​​​​​​

软测小生

微软 自动化测试 playwright webUI Web自动化测试

我是如何用几十个小时完成自己的3个flag

Sandy

握草,这些研发事故30%我都干过!

小傅哥

Java 小傅哥 28天写作 线上事故 系统秒杀

智能停车管理系统搭建,智慧小区智能化解决方案

t13823115967

智慧小区

Java 并发编程之 JMM & volatile 详解

vivo互联网技术

Java volatile JMM 指令重排序

DAPP软件开发|DAPP系统APP开发

系统开发

什么是ReadWriteMany?

焱融科技

Kubernetes 云原生 存储 焱融科技 持久化存储

十八般武艺玩转GaussDB(DWS)性能调优:SQL改写

华为云开发者联盟

数据库 sql 性能优化 GaussDB 算子

拍乐云语音聊天室SDK,助力非洲版陌陌“Mochat”打造粉丝经济

拍乐云Pano

音视频 RTC 语音聊天室 出海社交 社交泛娱乐

IndexedDB详解

程序那些事

大前端 程序那些事 indexedDB webtech 浏览器技术

软件测试--数据库基础知识

测试人生路

数据库 软件测试

开发效率提升15倍!批流融合实时平台在好未来的应用实践

Apache Flink

流计算 fink

人脸识别门禁系统搭建,智慧小区实施方案

t13823115967

智慧平安小区平台开发

网络请求是如何发送出去的

kof11321

网络

上链DAPP软件开发|上链DAPP系统APP开发

系统开发

【JS】防止浏览器控制台被直接查看(1)

德育处主任

JavaScript 大前端 js 28天写作

架构师 3 期 3 班 -week7- 作业

zbest

作业 week7

没人告诉过你更复杂的缓存穿透怎么解决

艾小仙

架构

SpringCloud 从入门到精通 04---支付模块 02

Felix

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