PDA

Просмотр полной версии : Копирование прямоугольной области, под маской


alexandrratush
11.03.2014, 01:10
Здравствуйте! Помогите решить следующую проблему.
Есть компонент для редактирования аватара пользователя (можно перетягивать картинку).
В этом компоненте есть контейнер для аватара, на него накладывается маска. В него добавляется графический объект. После нужно скопировать эту область под маской.

В итоге есть две проблемы, над которыми просидел целый день:
1. Почему обрезается картинка, если переместить ее вправо или вниз до упора. И как это исправить?
2. Как убрать отступы слева и сверху у скопированной картинки? Как видно она добавляется в контейнер, который должен соприкасаться с черной линией, и верхней границей ролика, но этого не происходит.

Примечание: Если этот компонент размещен на сцене в точке (0;0), то все работает отлично.

Код главного класса:
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.display.Sprite;


public class Main extends MovieClip {

private var _containerImage:Sprite = new Sprite();


public function Main() {
// Компонент
_componentAvatar.addAvatar(new TestMC());

// Контейнер изображения
_containerImage = new Sprite();
addChild(_containerImage);

// Кнопка
_btnSaveImage.addEventListener(MouseEvent.CLICK, saveHandler);
}

private function saveHandler(e:MouseEvent):void {

while (_containerImage.numChildren > 0) _containerImage.removeChildAt(0);

// Добавляем в контейнер копию из нашего компонента
_containerImage.addChild(_componentAvatar.avatarImage);
_containerImage.x = 275;
_containerImage.y = 0;
}
}
}



Код компонента:
package ui {

import flash.display.Sprite;
import flash.display.DisplayObject;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.events.Event;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.display.Bitmap;
import flash.display.PixelSnapping;
import flash.display.BitmapData;


public class ComponentAvatar extends Sprite {

private var _contAvatar:Sprite;
private var _mask:Sprite;
private var _boundsRect:Rectangle;


//- CONSTRUCTOR -------------------------------------------------------------------------------------------

public function ComponentAvatar() {
_contAvatar = new Sprite();
_contAvatar.buttonMode = true;
_contAvatar.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
addChild(_contAvatar);

createMask();

_boundsRect = getRect(this);

if (stage) init(null);
else addEventListener(Event.ADDED_TO_STAGE, init);
}


//- PUBLIC & INTERNAL METHODS -----------------------------------------------------------------------------

public function addAvatar(d:DisplayObject):void {
while (_contAvatar.numChildren > 0) _contAvatar.removeChildAt(0);

_contAvatar.scaleX = _contAvatar.scaleY = 1;
_contAvatar.x = _contAvatar.y = 0;
_contAvatar.addChild(d);

var minScaleX:Number = 200 / _contAvatar.width;
var minScaleY:Number = 200 / _contAvatar.height;
// _minScale = (minScaleX > minScaleY) ? minScaleX : minScaleY;

dispatchEvent(new Event(Event.ADDED));
}


//- PRIVATE & PROTECTED METHODS ---------------------------------------------------------------------------

private function createMask():void {
_mask = new Sprite();
_mask.graphics.beginFill(0x000000);
_mask.graphics.drawRoundRect(2, 2, width - 4, height - 4, 15, 15);
_mask.graphics.endFill();

addChild(_mask);

_contAvatar.mask = _mask;
}

private function moveCorrection():void {
// move to right
if (_contAvatar.x > _boundsRect.topLeft.x) {
_contAvatar.x = _boundsRect.topLeft.x;
}

// move to bottom
if (_contAvatar.y > _boundsRect.topLeft.y) {
_contAvatar.y = _boundsRect.topLeft.y;
}

// move left
if (_contAvatar.x < _boundsRect.bottomRight.x - _contAvatar.width) {
_contAvatar.x = _boundsRect.bottomRight.x - _contAvatar.width;
}

// move top
if (_contAvatar.y < _boundsRect.bottomRight.y - _contAvatar.height) {
_contAvatar.y = _boundsRect.bottomRight.y - _contAvatar.height;
}
}

private function cropBitmap( displayObject:DisplayObject, xC:Number = 0, yC:Number = 0, widthC:Number = 0, heightC:Number = 0 ):Bitmap {
if (!widthC) widthC = displayObject.width;
if (!heightC) heightC = displayObject.height;

var cropArea:Rectangle = new Rectangle(0, 0, widthC, heightC );

var bmpd:BitmapData = new BitmapData( widthC, heightC, true, 0x000000 );

var croppedBitmap:Bitmap = new Bitmap( bmpd, PixelSnapping.ALWAYS, true );

var cropMatrix:Matrix = croppedBitmap.transform.matrix;
cropMatrix.translate( -xC, -yC );

bmpd.draw( displayObject, cropMatrix, null, null, cropArea, true );

return croppedBitmap;
}


//- EVENT HANDLERS ----------------------------------------------------------------------------------------

private function init(e:Event):void {
if (e) removeEventListener(Event.ADDED_TO_STAGE, init);

stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}

private function mouseDownHandler(e:MouseEvent):void {
_contAvatar.startDrag();
stage.addEventListener(MouseEvent.MOUSE_UP, stageMouseUpHandler);
}

private function stageMouseUpHandler(e:MouseEvent):void {
_contAvatar.stopDrag();
}

private function enterFrameHandler(e:Event):void {
moveCorrection();
}


// - GETTER & SETTER --------------------------------------------------------------------------------------

public function get avatarImage():DisplayObject {
var ltPoint:Point = _contAvatar.globalToLocal( new Point(0, 0) );
return cropBitmap( _contAvatar, ltPoint.x, ltPoint.y, x + ltPoint.x + 200, y + ltPoint.y + 200 );
}
}
}


Исходник демки CS6:
30577

Вот демо:
Main.swf

Isfet
11.03.2014, 06:33
а вас не смущает что размер обрезки равен размеру маски ?
30579

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

Насчет отступов, сделайте еще один контейнер, в котором битмап будет храниться без отступов, внутри него делайте маску, и относительно него копируйте.
И вообще у вас должно быть две КОНСТАНТЫ,
WIDTH = 200;
HEIGHT = 200;
и относительно них вы пляшете, а не относительно абстрактного width и height вашего компонента, размер которых динамический и изменяется в зависимости от контента, и поведения которых сложно предугадать.

alexandrratush
11.03.2014, 14:19
Большое спасибо за советы, которые помогли очень.
Да вы правы все это через маску. Вставил пока костыль, когда будет время разберусь с этим.

Вот типо так работает: :D

public function get avatarImage():DisplayObject {
var ltPoint:Point = _contAvatar.globalToLocal(_leftTopPoint);

_contAvatar.mask = null;

var bm:Bitmap = DisplayUtils.cropBitmap( _contAvatar, ltPoint.x, ltPoint.y, 200, 200 );

_contAvatar.mask = _mask;

return bm;
}


Насчет отступов, сделайте еще один контейнер, в котором битмап будет храниться без отступов, внутри него делайте маску, и относительно него копируйте.
Вот это если честно не понял.

не нужно подписываться на энтерфрейм(из-за него у вас дергается изображение, когда перетаскиваешь его к краю), подписывайте стейдж на маусмув.
У меня просто есть эффект зума, так что я решил что это лучший вариант.

И вообще у вас должно быть две КОНСТАНТЫ,
Это тоже не выход, так как компонент будет иметь разные размеры в одном проекте.

Isfet
11.03.2014, 14:45
Вот это если честно не понял.

сделать контейнер(и сдвинуть его, а не битмапу), а внутри него битмапа будет лежать в координатах (0,0), и маска тоже.

У меня просто есть эффект зума, так что я решил что это лучший вариант.

почему не сделать 2 обработчика? move и wheel


Это тоже не выход, так как компонент будет иметь разные размеры в одном проекте.

значит не константы, а переменные, которые будут высчитываться 1 раз, смысл в том чтобы не использовать width , так как он может измениться при добавлении/сдвигании/растягивании чилда.