API растровых данных, .draw из преобразованного спрайта

Я использую api растровых данных, чтобы позволить пользователю захватывать изображение с помощью своей веб-камеры, редактировать его и сохранять на своем жестком диске.

Мне успешно удалось обрезать растровые данные с помощью матрицы преобразования, однако проблема в том, что любые преобразования, примененные к захваченному изображению (с помощью инструмента преобразования Senocular), не отражаются в сохраненном изображении. Очевидно, это как-то связано с командой .draw, но я не понимаю, что?

Как я могу получить растровые данные .draw, чтобы отразить преобразования масштаба и поворота, примененные к захваченному изображению?

Вы можете просмотреть приложение по адресу: http://s46264.gridserver.com/dev/dave/pb-photo/index.html (просто щелкните захваченное изображение, чтобы включить инструменты масштабирования / поворота), а исходный код / ​​классы заархивированы по адресу: http://s46264.gridserver.com/dev/dave/pb-photo/pb-photo.zip

Приветствуются любые разъяснения.

Спасибо

Код:

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.geom.Matrix;
import flash.net.FileReference;
import com.adobe.images.JPGEncoder;
import com.senocular.display.transform.*;

// create container for captured image to apply Transform Tool to
var box:Sprite = new Sprite();
addChild(box);
box.graphics.beginFill(0xAACCDD);
box.graphics.drawRect(-160, -120, 320, 240); // xreg, yreg, width, height (x-y = width-height / 2 to set centered registration point)
box.x = 520;
box.y = 140;

// create the Transform Tool
var tool:TransformTool = new TransformTool(new ControlSetStandard());
addChild(tool);

// select the box with the transform tool when clicked. 
// deselect when clicking on the stage
box.addEventListener(MouseEvent.MOUSE_DOWN, tool.select);
stage.addEventListener(MouseEvent.MOUSE_DOWN, tool.deselect);

var snd:Sound = new camerasound(); //new sound instance for the "capture" button click

var bandwidth:int = 0; // Maximum amount of bandwidth that the current outgoing video feed can use, in bytes per second.
var quality:int = 100; // This value is 0-100 with 1 being the lowest quality. 

var cam:Camera = Camera.getCamera();
cam.setQuality(bandwidth, quality);
cam.setMode(320,240,30,false); // setMode(videoWidth, videoHeight, video fps, favor area)
var video:Video = new Video();
video.attachCamera(cam);
video.x = 20;
video.y = 20;
addChild(video);

var bitmapData:BitmapData = new BitmapData(video.width,video.height);

var bitmap:Bitmap = new Bitmap(bitmapData);
bitmap.x = -160;
bitmap.y = -120;
box.addChild(bitmap);

capture_mc.buttonMode = true;
capture_mc.addEventListener(MouseEvent.CLICK,captureImage);

function captureImage(e:MouseEvent):void {
    snd.play();
    bitmapData.draw(video);
    save_mc.buttonMode = true;
    save_mc.addEventListener(MouseEvent.CLICK, onSaveJPG);
    save_mc.alpha = 1;
}

save_mc.alpha = .5;

var crop:Matrix = new Matrix();
crop.createBox(1, 1, 0, box.x-crop_mc.x, box.y-crop_mc.y);

function onSaveJPG(e:Event):void{

    var bmp:BitmapData = new BitmapData(crop_mc.width, crop_mc.height, true);
    bmp.draw(box, crop);

    var encoder:JPGEncoder = new JPGEncoder(100);

    // Save the encoded byte array to a local file.
    var f:FileReference = new FileReference();
    f.save( encoder.encode(bmp), "imagem.jpg" );

}

person digitalpencil    schedule 23.06.2011    source источник


Ответы (3)


У вас есть два варианта: 1 - скопировать все преобразования в матрицу и передать их методу draw () в качестве второго аргумента, 2 - нарисовать нетрансформированный контейнер, а не преобразованное растровое изображение.

Второй подход, очевидно, самый простой. Но в любом случае, я думаю, вы должны иметь возможность получить transform.matrix из контейнера, который преобразует объект в инструменте senocular (хотя никогда не использовал его, поэтому не могу поделиться деталями).

Итак, пример первого способа:

import flash.display.Sprite;
import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.geom.Matrix;
import flash.display.Bitmap;

// create some subject

var test:Sprite = new Sprite();
test.graphics.beginFill(0);
test.graphics.drawRect(0, 0, 100, 50);
test.graphics.endFill();

// transform

test.x = 50;
test.y = 50;
test.scaleX = 1.5;
test.scaleY = 0.5;
test.rotation = 45;

addChild(test);

// draw transformed subject

// test boundaries in test's parent coordinate space
var rect:Rectangle = test.getRect(test.parent);
var bmp:BitmapData = new BitmapData(rect.width, rect.height, false, 0xFFFF0000);

// copy transform matrix
var matrix:Matrix = test.transform.matrix;

// translate test's matrix to match it with bitmap
matrix.translate(-rect.x, -rect.y);

bmp.draw(test, matrix);

// show what we've got
var bitmap:Bitmap = new Bitmap(bmp);
bitmap.x = 200;
bitmap.y = 50;
addChild(bitmap);

Пример второго способа:

import flash.display.Sprite;
import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.geom.Matrix;
import flash.display.Bitmap;

// create some subject

var container:Sprite = new Sprite();

var test:Sprite = new Sprite();
test.graphics.beginFill(0);
test.graphics.drawRect(0, 0, 100, 50);
test.graphics.endFill();

// transform

test.x = 50;
test.y = 50;
test.scaleX = 1.5;
test.scaleY = 0.5;
test.rotation = 45;

container.x = 50;
container.y = 50;

addChild(container);
container.addChild(test);

// draw transformed subject

// container boundaries in it's own coordinate space.
// we assume, that container is not transformed.
var rect:Rectangle = container.getRect(container);
var bmp:BitmapData = new BitmapData(rect.width, rect.height, false, 0xFFFF0000);

// translate container's matrix to match it with bitmap
var matrix:Matrix = new Matrix();
matrix.translate(-rect.x, -rect.y);

bmp.draw(container, matrix);

// show what we've got
var bitmap:Bitmap = new Bitmap(bmp);
bitmap.x = 300;
bitmap.y = 100;
addChild(bitmap);

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

person Michael Antipin    schedule 23.06.2011
comment
спасибо, это очень помогло. есть некоторые проблемы с точками регистрации, установленными инструментом преобразования, но теперь он отрисовывается из преобразованного объекта. - person digitalpencil; 27.06.2011

Из справочника BitmapData.draw :

Исходный экранный объект не использует никаких примененных преобразований для этого вызова. Он рассматривается в том виде, в каком он существует в библиотеке или файле, без преобразования матрицы, преобразования цвета и режима наложения. Чтобы нарисовать экранный объект (например, фрагмент ролика) с использованием его собственных свойств преобразования, вы можете скопировать его объект свойства transform в свойство transform объекта Bitmap, который использует объект BitmapData.

Таким образом, вам нужно скопировать свойство преобразования блока в растровое изображение, созданное с помощью команды draw.

person Jorjon    schedule 23.06.2011

Я не могу точно сказать, есть ли проблема с вашим кодом, но похоже, что она есть ... Вы пробовали создать растровое изображение из ваших обрезанных bitmapData?

var bmp:BitmapData = new BitmapData(crop_mc.width, crop_mc.height, true);
bmp.draw(box, crop);
var bitmap = new Bitmap (bmp);
stage.addChild (bitmap);

Как выглядит это растровое изображение?

Если он по-прежнему выглядит как необрезанная версия, мне кажется, что ваша проблема, вероятно, в том, что вы рисуете не тот контейнер. Вы можете попробовать переместить клип «коробку» в другой контейнер и нарисовать этот «внешний» контейнер при сохранении изображения.

Я не уверен, как работает инструмент senocular, но если «инструмент» хранит измененные BitmapData, вы также можете попробовать захватить инструмент.

Надеюсь, это даст вам некоторые идеи ...

person sapptime    schedule 23.06.2011