суббота, 21 марта 2009 г.

Сохранение картинки из flash

В этом уроке я расскажу, как сделать возможным сохранение ролика или его части (мувиклипа) на диск в формате рисунка (jpg). Данный урок является продолжением серии уроков по созданию графического редактора (рисование линий), но может использоваться и в совершенно других целях.

1. Для начала работы нам потребуется дополнительный класс JPGEncoder, который находится в дополнительной библиотеке Adobe Core Library. Скачать его можно на этой странице. Разархивируйте архив и найдите папку com (\as3corelib-.92.1\src\com) Ее нужно скопировать в каталог, где хранится Ваш *.fla файл.

2. В самое начало нашего кода помещаем строчку:
  1. import com.adobe.images.JPGEncoder;


тем самым мы импортировали в наш скрипт класс JPGEncoder, который нужен нам для преобразования векторного изображения в растровое.

3. Поместим в нашу флешку кнопку и присвоем ей имя 'saveBtn':


После чего присвоим ей событие 'saveImage' (добавим в код вот эту строчку):

  1. saveBtn.addEventListener (MouseEvent.CLICK, saveImage);


4. Напишем функцию saveImage, которая и будет в последствии сохранять наш рисунок
  1. function saveImage (event:MouseEvent) : void {

  2.  

  3. }

  4.  



Добавим в эту функцию такой код:
  1. var jpgSource:BitmapData = new BitmapData (550, 400);

  2. jpgSource.draw(this);

  3. var jpgEncoder:JPGEncoder = new JPGEncoder(95);

  4. var jpgStream:ByteArray = jpgEncoder.encode(jpgSource);

  5.  


Первая строчка создает объект BitmapData с шириной в 550 и высотой в 400 пикселей. Вторая строчка прорисовывает весь флеш ролик в этом объекте (впоследствии мы модифицируем код и сделаем так, чтобы сохранялся только рисунок)
Третья строчка кодирует полученное изображение в формате jpg в качестве 95%, для изменения качества нужно вписать вместо 95 другое значение...
Четвертая строчка сохраняет изображение как последовательность битов, чтобы передать ее в пхп скрипт, который и займется сохранением файла.

5. Создание пхп скрипта для сохранения.
Ниже представлен пхп код, который будет сохранять эот файл на локальный компьютер. Пхп - программисту не составит сложности модифицировать его таким образом, чтобы, например, сохранять его на сервере, или производить с ним какие - либо действия. Сам код, как и основные моменты данного урока я подсмотрел тут. Итак,

  1. <? if (isset($GLOBALS["HTTP_RAW_POST_DATA"]))

  2. {

  3. // get bytearray

  4. $jpg = $GLOBALS["HTTP_RAW_POST_DATA"];

  5.  

  6. // add headers for download dialog-box

  7. header('Content-Type: image/jpeg');

  8. header("Content-Disposition: attachment; filename=".$_GET['name']);

  9. echo $jpg;

  10. }

  11. ?>



Этот пхп файл необходимо сохранить на веб (или локальном сервере) для его выполнения.
!Важно! При сохранении пхп файла в кодировке utf8, данный пример может не сработать по некоторым причинам, поэтому рекомендую сохранять его в западноевропейской кодировке.

6. Передача в пхп картинки из flash
Добавим в нашу функцию 'saveImage' следующий код:
  1. var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");

  2. var jpgURLRequest:URLRequest = new URLRequest('http://ecomodul.com.ua/flash_tests/saveImage.php?name=actscript.jpg');

  3. jpgURLRequest.requestHeaders.push(header);

  4. jpgURLRequest.method = URLRequestMethod.POST;

  5. jpgURLRequest.data = jpgStream;

  6. navigateToURL(jpgURLRequest, "_self");


в итоге наша функция 'saveImage' будет иметь следующий вид :
  1. function saveImage (event:MouseEvent) : void {

  2.  

  3. var jpgSource:BitmapData = new BitmapData (550, 400);

  4. jpgSource.draw(this);

  5. var jpgEncoder:JPGEncoder = new JPGEncoder(95);

  6. var jpgStream:ByteArray = jpgEncoder.encode(jpgSource);

  7.  

  8. var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");

  9. var jpgURLRequest:URLRequest = new URLRequest('http://ecomodul.com.ua/flash_tests/saveImage.php?name=actscript.jpg');

  10. jpgURLRequest.requestHeaders.push(header);

  11. jpgURLRequest.method = URLRequestMethod.POST;

  12. jpgURLRequest.data = jpgStream;

  13. navigateToURL(jpgURLRequest, "_self");

  14.  

  15. }



Причем, вместо 'http://ecomodul.com.ua/flash_tests/saveImage.php' следует вписать адрес пхп-скрипта, созданного в 5м пункте, а вместо 'actscript.jpg' нужно вписать любое другое название, под которым Вы хотите сохранить картинку.

7. Вот пример того, как это должно выглядеть

Если что-то не получилось, то как всегда можно взять уже готовенькое.
Но эта флешка сохраняет не только наш рисунок, но и всю себя, поэтому нужно модифицировать наш код...

9. Нарисуем во flash(е) белый прямоугольник с черной границей (цвета могут быть другими), сохраним его как мувиклип и присвоим имя 'drawSurface'. Это и будет наше "полотно" для рисования:

10. Создайте пустой мувиклип и поместите его в 'drawSurface' с координатами (0;0). Назовите его 'drawing':



11. Создайте слой-маску, которая будет маскировать 'root.drawSurface.drawing'. Причем маска должна полностью совпадать по координатам с белой подложкой 'drawSurface'(а):
Эта маска нужна для того, чтобы линия, которая будет выходит за грани 'полотна' не отображалась.

12. Теперь модифицируем код. Для начала сделаем так, чтобы линия рисовалась не непосредственно в ролик, а в мувиклип 'drawSurface':
Найдем в коде следующие строки:
  1. function startDrawing(event:MouseEvent):void{

  2. this.graphics.lineStyle(this.sizeSlider.value, this.cp.selectedColor, this.opacitySlider.value); //Линия имеет ширину, прозрачность и цвет, равную положениям компонентов

  3. this.graphics.moveTo( mouseX, mouseY);////Ставим "начало" линии в точку положения курсора

  4. drawing = true;//Начинаем рисовать

  5. }


И изменим их на:
  1. function startDrawing(event:MouseEvent):void{

  2. this.drawSurface.drawing.graphics.lineStyle(this.sizeSlider.value, this.cp.selectedColor, this.opacitySlider.value); //Линия имеет ширину, прозрачность и цвет, равную положениям компонентов

  3. this.drawSurface.drawing.graphics.moveTo(drawSurface.mouseX,drawSurface.mouseY);//Ставим "начало" линии в точку положения курсора

  4. drawing = true;//Начинаем рисовать

  5. }


Теперь изменим:
  1. function drawIt (event:MouseEvent){

  2. if(drawing){//Проверка переменной drawing

  3. this.graphics.lineTo(mouseX,mouseY);//Линия ведется к новой координате

  4. }

  5.  

  6. }


на
  1. function drawIt (event:MouseEvent){

  2. if(drawing){//Проверка переменной drawing

  3. this.drawSurface.drawing.graphics.lineTo(this.drawSurface.mouseX, this.drawSurface.mouseY);//Линия ведется к новой координате

  4. }

  5.  

  6. }


И последнее:
  1. function changeLineStyle (event:Event) : void {

  2. this.graphics.lineStyle(this.sizeSlider.value, this.cp.selectedColor, this.opacitySlider.value);//Линия меняет ширину, прозрачность и цвет, в зависимости от положения компонентов

  3. }


На:
  1. function changeLineStyle (event:Event) : void {

  2. this.drawSurface.drawing.graphics.lineStyle(this.sizeSlider.value, this.cp.selectedColor, this.opacitySlider.value);//Линия меняет ширину, прозрачность и цвет, в зависимости от положения компонентов

  3. }



13. Теперь наш листинг выглядит таким образом:

import com.adobe.images.JPGEncoder;
// Переменная drawing будет определять, рисовать ли линию в данный момент.
var drawing:Boolean = false;

// Присвоим ролику события
stage.addEventListener(MouseEvent.MOUSE_DOWN, startDrawing); //Если мышь нажата, начинает рисовать
stage.addEventListener(MouseEvent.MOUSE_MOVE, drawIt); // При движении мыши рисует линию
stage.addEventListener(MouseEvent.MOUSE_UP, stopDrawing); // Если мышь отпущена, прекращает рисовать

this.cp.addEventListener(Event.CHANGE, changeLineStyle);
this.sizeSlider.addEventListener(Event.CHANGE, changeLineStyle);
this.opacitySlider.addEventListener(Event.CHANGE, changeLineStyle);
saveBtn.addEventListener (MouseEvent.CLICK, saveImage);

function startDrawing(event:MouseEvent):void{
this.drawSurface.drawing.graphics.lineStyle(this.sizeSlider.value, this.cp.selectedColor, this.opacitySlider.value); //Линия имеет ширину, прозрачность и цвет, равную положениям компонентов
this.drawSurface.drawing.graphics.moveTo( this.drawSurface.mouseX, this.drawSurface.mouseY);//Ставим "начало" линии в точку положения курсора
drawing = true;//Начинаем рисовать
}

function drawIt (event:MouseEvent){
if(drawing){//Проверка переменной drawing
this.drawSurface.drawing.graphics.lineTo(this.drawSurface.mouseX,this.drawSurface.mouseY);//Линия ведется к новой координате
}

}

function stopDrawing (event:MouseEvent) :void {
drawing = false;//Прекращаем рисовать
}

function changeLineStyle (event:Event) : void {
this.drawSurface.drawing.graphics.lineStyle(this.sizeSlider.value, this.cp.selectedColor, this.opacitySlider.value);//Линия меняет ширину, прозрачность и цвет, в зависимости от положения компонентов
}

function saveImage (event:MouseEvent) : void {

var jpgSource:BitmapData = new BitmapData (550, 400);
jpgSource.draw(this);
var jpgEncoder:JPGEncoder = new JPGEncoder(95);
var jpgStream:ByteArray = jpgEncoder.encode(jpgSource);

var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");
var jpgURLRequest:URLRequest = new URLRequest('http://ecomodul.com.ua/flash_tests/saveImage.php?name=actscript.jpg');
jpgURLRequest.requestHeaders.push(header);
jpgURLRequest.method = URLRequestMethod.POST;
jpgURLRequest.data = jpgStream;
navigateToURL(jpgURLRequest, "_self");

}


14. Если вы запустите получившийся ролик, то увидите, что рисование происходит только на "полотне" и не выходит за его пределы. Остается последнее: сделать так, чтобы при нажатии кнопки "сохранить" флеш сохранял только наш рисунок, для этого вместо:


jpgSource.draw(this);

напишем такую строчку:

jpgSource.draw(drawSurface);

в итоге при нажатии кнопки 'saveBtn' будет сохраняться уже наш рисунок. Осталось изменить его ширину и высоту:
Поменяем строчку:

var jpgSource:BitmapData = new BitmapData (550, 400);

на:

var jpgSource:BitmapData = new BitmapData (this.drawSurface.width, this.drawSurface.height);

Теперь можно проверить. Мой пример тут
А исходник тут

Комментариев нет:

Отправить комментарий