До появления ActionScript 3 единственным вариантом сохранить изображение на сервере была передача значения каждого пикселя объекта BitmapData серверному скрипту. Теперь с появлением объекта ByteArray и с помощью последнего релиза AMFPHP мы можем с легкостью передать объект BitmapData в виде последовательности байтов.
Оригинал статьи: Send and Receive ByteArray to AMFPHP
Автор: Alessandro Crugnola
Перевод: Алексей «Vooparker» Аникутин
Перед прочтением этой статьи автор советует ознакомиться с этими материалами:
1. Экипировка
Чтобы успешно справиться c этим уроком нам потребуются:
2. Настройка аmfphp-проекта
Сначала настроим серверную часть нашего проекта. Для это в папке amfphp/services создайте директорию: "tutorials/amfphp_bytearray". И в только что созданной директории создайте файл SaveJPEG.php со следующим содержанием:
-
<?php
-
class SaveJPEG
-
{
-
var $output_dir = "temp";
-
var $server_url = "http://www.sephiroth.it/amfphp2/services/tutorials/amfphp_bytearray/";
-
-
/**
-
* Save image from the given bytearray
-
* and return the path of the saved image
-
*/
-
function SaveAsJPEG($ba, $compressed = false)
-
{
-
-
$data = $ba->data;
-
if($compressed)
-
{
-
{
-
} else {
-
}
-
}
-
file_put_contents($this->output_dir . "/rawdata.jpeg", $data);
-
return $this->server_url . $this->output_dir . "/rawdata.jpeg";
-
}
-
-
/**
-
* Save file from a given bytearray
-
* and return a ByteArray from the saved file
-
*/
-
function SaveAsByteArray($ba, $compresses = false)
-
{
-
-
$data = $ba->data;
-
if($compressed)
-
{
-
{
-
} else {
-
}
-
}
-
file_put_contents($this->output_dir . "/rawdata.rgb", $data);
-
}
-
}
-
?>
В той же директории amfphp_bytearray создайте пустую директорию temp c маской доступа 755. Мы будем использовать эту директорию для хранения временных файлов, которые были получены из flash.
В нашем классе всего два метода: SaveAsJPEG и SaveAsByteArray. Оба принимают два параметра:
- экземпляр ByteArray
- и флаг указывающий сжата ли передаваемая последовательность байтов
Так как метод compress класса ByteArray использует алгоритм сжатия zlib, необходимо чтобы в вашей установке PHP была доступна функция gzuncompress.
2.1 SaveAsJPEG
Этот метод получает из flash последовательность байтов, которая представляет собой jpeg файл. По этой причине, мы просто сохраняем файл как 'rawdata.jpg', а так как это изображение будет валидным jpeg файлом, и мы просто скажем flash загрузить его как обычное изображение.
2.2 SaveAsByteArray
В этом случае мы сохраним последовательность байтов так как есть, это означает, что изображение не может быть загружено как обычный файл изображения (вы также не сможете просмотреть его в браузере). Так что, во втором примере мы вернем flash экземпляр php ByteArray, содержащий данные сохраненного файла (используя для этого file_get_content).
Flash получит его как последовательность байтов и, таким образом, мы сможем с легкостью использовать его для создания экземпляра BitmapData.
3. Flex
Давайте посмотрим на наш .mxml файл:
-
<?xml version="1.0" encoding="utf-8"?>
-
<mx:Application
-
xmlns:mx="http://www.adobe.com/2006/mxml"
-
layout="absolute"
-
xmlns:display="flash.display.*"
-
xmlns:ns1="http://www.sephiroth.it/2006/mxml">
-
<mx:RemoteObject id="service" showBusyCursor="true" destination="amfphp" fault="faultHandler(event)" source="tutorials.amfphp_bytearray.SaveJPEG">
-
<mx:method name="SaveAsJPEG" result="savejpeg_resultHandler(event)" />
-
<mx:method name="SaveAsByteArray" result="savebyte_resultHandler(event)" />
-
</mx:RemoteObject>
-
<mx:Style>
-
NumericPopUp {
-
slider-border-style:solid;
-
slider-border-color:#999999;
-
slider-background-color:#EBEBEB;
-
direction:horizontal;
-
}
-
-
Application {
-
background-color: #FFFFFF;
-
}
-
</mx:Style>
-
<mx:Script>
-
<![CDATA[
-
import mx.core.UIComponent;
-
import mx.controls.Alert;
-
import mx.controls.SWFLoader;
-
import com.adobe.images.JPGEncoder;
-
import mx.rpc.events.FaultEvent;
-
import mx.rpc.events.ResultEvent;
-
-
private var send_compressed:Boolean = false; // send always uncompressed bytearrays (i.e. your server doesn not support "gzuncompress")
-
private var encoder:JPGEncoder;
-
-
/**
-
* Default handler for the remote SaveAsJPEG function
-
*/
-
private function savejpeg_resultHandler(event:ResultEvent):void
-
{
-
if(event.result || event.result is String)
-
{
-
var path:String = event.result as String;
-
trace(path);
-
-
var swf_loader:SWFLoader = preview_box.getChildByName("preview") as SWFLoader;
-
swf_loader.showBusyCursor = true;
-
swf_loader.load(path + "?rand=" + new Date().getTime());
-
-
image_size.text = "Loading...";
-
}
-
}
-
-
/**
-
* Default handler for the remote SaveAsByteArray function
-
*/
-
private function savebyte_resultHandler(event:ResultEvent):void
-
{
-
var ba:ByteArray = event.result as ByteArray;
-
var ui_loader:UIComponent = preview_box.getChildByName("preview") as UIComponent;
-
image_size.text = 'ByteArray size: ' + Math.round(((ba.length/4)/1024)*100)/100 + ' Kb'
-
-
try
-
{
-
ba.uncompress();
-
} catch(err:Error)
-
{
-
}
-
-
var data:BitmapData = new BitmapData(original_image.width, original_image.height, false, 0);
-
var bmp:Bitmap = new Bitmap(data);
-
bmp.name = "image";
-
data.setPixels(data.rect, ba);
-
-
ui_loader.addChild(new Bitmap(data));
-
ui_loader.width = data.width;
-
ui_loader.height = data.height;
-
-
}
-
-
/**
-
* Default fault handler
-
*/
-
private function faultHandler(event:FaultEvent):void
-
{
-
Alert.show(event.fault.faultString, "Error: " + event.fault.faultCode);
-
trace(event.fault.message);
-
}
-
-
/**
-
* Save the image using the JPEGEncoder class
-
*/
-
private function saveJpegHandler(event:MouseEvent):void
-
{
-
removeImages();
-
-
var swf_loader:SWFLoader = new SWFLoader();
-
swf_loader.autoLoad = true;
-
swf_loader.name = "preview";
-
swf_loader.addEventListener(Event.COMPLETE, function(event:Event):void { image_size.text = 'Image size: ' + (SWFLoader(event.target).bytesTotal/1024).toPrecision(3) + ' Kb' });
-
preview_box.addChildAt(swf_loader, 0);
-
-
var bmpdata:BitmapData = Bitmap(original_image.content).bitmapData;
-
var ba:ByteArray;
-
-
encoder = new JPGEncoder(jpeg_quality.value);
-
ba = encoder.encode( bmpdata );
-
-
if(send_compressed)
-
ba.compress();
-
-
service.getOperation("SaveAsJPEG").send(ba, send_compressed);
-
-
image_size.text = "Sending..."
-
}
-
-
/**
-
* Save the image using only ByteArray derived from
-
* BitmapData.getPixels
-
*/
-
private function saveByteHandler(event:MouseEvent):void
-
{
-
removeImages();
-
-
var ui_loader:UIComponent = new UIComponent();
-
ui_loader.name = "preview";
-
preview_box.addChildAt(ui_loader, 0);
-
-
var bmpdata:BitmapData = Bitmap(original_image.content).bitmapData;
-
var arr:ByteArray = Bitmap(original_image.content).bitmapData.getPixels(new Rectangle(0,0,bmpdata.width, bmpdata.height));
-
-
if(send_compressed)
-
arr.compress();
-
-
arr.position = 0;
-
service.getOperation("SaveAsByteArray").send(arr, send_compressed);
-
-
image_size.text = "Sending..."
-
}
-
-
private function removeImages():void
-
{
-
if(preview_box.getChildByName("preview"))
-
preview_box.removeChild(preview_box.getChildByName("preview"));
-
-
image_size.text = "";
-
}
-
-
]]>
-
</mx:Script>
-
<mx:VBox left="5" top="5" right="5" bottom="5">
-
<ns1:LabelledBox title="Original Image" direction="horizontal" paddingBottom="20" paddingLeft="20" paddingRight="20" paddingTop="20" labelPlacement="left" labelPadding="10" cornerRadius="5" id="original_box">
-
<mx:Image x="10" y="33" source="@Embed('images/284541843_b77b917989[1].jpg')" id="original_image"/>
-
<mx:Grid x="269" y="33">
-
<mx:GridRow width="100%" height="100%">
-
<mx:GridItem width="100%" height="100%" verticalAlign="middle">
-
<mx:Label text="Jpeg quality"/>
-
</mx:GridItem>
-
<mx:GridItem width="100%" height="100%" verticalAlign="middle">
-
<ns1:NumericPopUp id="jpeg_quality" minimum="1" maximum="100" stepSize="1" value="50" direction="horizontal">
-
</ns1:NumericPopUp>
-
</mx:GridItem>
-
</mx:GridRow>
-
<mx:GridRow width="100%" height="100%">
-
<mx:GridItem width="100%" height="100%">
-
</mx:GridItem>
-
<mx:GridItem width="100%" height="100%" verticalAlign="middle">
-
<mx:Button label="Save as Jpeg" click="saveJpegHandler(event)" width="100%"/>
-
</mx:GridItem>
-
</mx:GridRow>
-
<mx:GridRow width="100%" height="100%">
-
<mx:GridItem width="100%" height="100%">
-
</mx:GridItem>
-
<mx:GridItem width="100%" height="100%" verticalAlign="middle">
-
<mx:Button label="Save as ByteArray" click="saveByteHandler(event)" width="100%"/>
-
</mx:GridItem>
-
</mx:GridRow>
-
<mx:GridRow width="100%" height="100%">
-
<mx:GridItem width="100%" height="100%" colSpan="2">
-
</mx:GridItem>
-
</mx:GridRow>
-
</mx:Grid>
-
</ns1:LabelledBox>
-
<ns1:LabelledBox id="preview_box" paddingBottom="20" paddingLeft="20" paddingRight="20" paddingTop="20" labelPlacement="left" labelPadding="10" cornerRadius="5" title="Saved Image" clipContent="false" minWidth="300" minHeight="100" direction="horizontal" width="{original_box.width}">
-
<mx:Grid>
-
<mx:GridRow width="100%" height="100%">
-
<mx:GridItem width="100%" height="100%" verticalAlign="middle">
-
<mx:Label text="" id="image_size" />
-
</mx:GridItem>
-
</mx:GridRow>
-
<mx:GridRow width="100%" height="100%">
-
</mx:GridRow>
-
</mx:Grid>
-
</ns1:LabelledBox>
-
</mx:VBox>
-
</mx:Application>
Для отправки данных на сервер у нас есть два метода: saveJpegHandler и saveByteHandler.
3.1 saveJpegHandler
Этот метод получает экземпляр BitmapData из оригинального изображения, и преобразует его в jpeg, используя JPEGEncoder, передавая в конструктор степень оптимизации jpeg изображения.
var bmpdata:BitmapData = Bitmap(original_image.content).bitmapData;
var ba:ByteArray;
encoder = new JPGEncoder(jpeg_quality.value);
ba = encoder.encode( bmpdata );
Сервер вернет строку, содержащую путь к сохраненному изображению, так что все что нам остается, так это загрузить файл используя SWFLoader.
swf_loader.load(path + "?rand=" + new Date().getTime());
Добавление параметра "?rand" позволяет обойти проблему с кэшированием браузером изображения.
3.2 saveByteHandler
Второй метод отправляет последовательность байтов amfphp, и получает ту же последовательность в качестве результата:
// get the original bitmapdata
var bmpdata:BitmapData = Bitmap(original_image.content).bitmapData;
// transform the bitmapdata into a bytearray
var arr:ByteArray = Bitmap(original_image.content).bitmapData.getPixels(new Rectangle(0,0,bmpdata.width, bmpdata.height));
Метод преобразует BitmapData в ByteArray с помощью метода класса BitmapData getPixels и отправляет на сервер.
Метод AMFPHP возвращает последовательность байтов, так что мы можем использовать ее, чтобы создать BitmapData, используя метод setPixel:
// server returns a bytearray
var ba:ByteArray = event.result as ByteArray;
// create a new bitmapdata to store into the resulting bytearray pixels
var data:BitmapData = new BitmapData(original_image.width, original_image.height, false, 0);
var bmp:Bitmap = new Bitmap(data);
// draw the bytearray into just created bitmapdata
data.setPixels(data.rect, ba);
// then add the bitmap to a new UIComponent
ui_loader.addChild(new Bitmap(data));
ui_loader.width = data.width;
ui_loader.height = data.height;
4. Загрузки
Вы также можете скачать исходные файлы к статье.



Известно ли что-нибудь о релизе 1.9 версии? Ведь чувак, который ее разрабатывал ушел из флеша...