Flex: Сохранение mx:image с примененными эффектами

Я загружаю изображение для управления, затем применяю некоторые эффекты, и когда я сохраняю изображение, оно сохраняется без эффектов. Что я должен делать?

Вот код:

private var byteArr2:ByteArray;
private var fileRef:FileReference = new FileReference(); 

public function process():void
{
        var ct:ColorTransform = new  ColorTransform();
        ct.redOffset = 99;
        ct.blueOffset = 11;
            ct.greenOffset = 22;
            currImg.transform.colorTransform = ct;
            callLater(toByteArray);
}

public function toByteArray():void
{
        var data:BitmapData = new BitmapData(currImg.width, currImg.width);
        data.draw(currImg);             
        var encod:JPEGEncoder = new JPEGEncoder(100);               
        byteArr2 = encod.encode(data);
}
public function saveFile():void 
{  
        fileRef.save(byteArr2,"NewFileName1.jpg");
} 
<mx:HBox>       
        <mx:VBox>           
            <s:Button x="69" y="98" label="open" click="open()()"/>
            <s:Button label="show" click="show()"/> 
            <s:Button label="process" click="process()"/>   
            <s:Button label="save" click="saveFile()"/> 
        </mx:VBox>
        <mx:Image id="currImg" width="200" height="300"/>
    </mx:HBox>

ОБНОВЛЕНИЕ Появляется новая проблема, так как я использую var data:BitmapData = new BitmapData(currImg.width, currImg.width); сохраненное изображение маленькое (размер как элемент управления изображением), но мне нужно сохранить изображение с исходным размером. С var data:BitmapData = Bitmap(currImg.content).bitmapData; получилось


person Sergey    schedule 05.01.2011    source источник
comment
+ Хорошо сформулированный вопрос и хороший пример кода. К сожалению, у меня нет ответа для вас.   -  person JeffryHouser    schedule 05.01.2011


Ответы (2)


Я бы нарисовал компонент в новом объекте BitmapData, а не использовал содержимое currImg. Это должно дать вам то, что нарисовано на экране, а не неизмененный контент. Что-то вроде этого:

var data:BitmapData = new BitmapData(currImg.width, currImg.width);
data.draw(currImg);

Надеюсь, это поможет.

person Wade Mueller    schedule 05.01.2011
comment
странно, но проблема осталась - person Sergey; 06.01.2011
comment
Хм, интересно, это потому, что вы сохраняете изображение до того, как изображение обновится, чтобы отразить преобразование? Вы можете попробовать кодировать/сохранить в отдельном методе, который вы вызываете с помощью callLater, что даст возможность сначала обновить изображение. Никаких гарантий, просто идея. - person Wade Mueller; 06.01.2011
comment
это просто пример кода, в полной версии эти действия находятся в отдельных методах - person Sergey; 06.01.2011
comment
Вызываются ли методы последовательно, другими словами, очищается ли очередь событий перед вызовом кодирования/сохранения? Если нет, callLater все еще может быть вам полезен. - person Wade Mueller; 06.01.2011
comment
да, я использую callLater для кодирования в массив байтов и после нажатия кнопки сохраняю его с помощью fileRef.save - person Sergey; 06.01.2011
comment
Ничего себе, не видя больше вашего кода, я в тупике. Один из обходных путей может состоять в том, чтобы обернуть ваше изображение в контейнер и нарисовать этот контейнер в растровое изображение вместо самого компонента изображения. Хотя сейчас я просто снимаю в темноте. Удачи. - person Wade Mueller; 06.01.2011
comment
Пробовали ли вы применить фильтр к объекту растровых данных после создания моментального снимка (вместо использования преобразования для компонента изображения)? ColorMatrixFilter может сделать то, чего вы пытаетесь достичь? Вы также можете применить объект ColorTransform к BitmapData с помощью BitmapData.colorTransform(). - person Chris Bos; 06.01.2011
comment
Кроме того, для обработки JPEGncoder требуется некоторое время, вы можете переместить его в обработчик файла сохранения (удалить вызов toByteArray из процесса, переместить код в saveFile). Мне также неясно, когда вызывается callLater... если это следующий кадр, это может быть до завершения рендеринга (поэтому преобразование все еще не применяется), хотя я всегда думал, что код выполняется после завершения рендеринга. . применение фильтра к BitmapData может избежать этой проблемы (поскольку это происходит сразу, а не при следующем обновлении рендеринга)? - person Chris Bos; 06.01.2011
comment
@Chris Bos: метод callLater в основном помещает вызов метода в конец очереди событий, что дает возможность обновиться. Я подумал, что это может помочь в этом случае, поскольку исходный код, опубликованный Сергеем, вызывал кодирование/сохранение сразу после установки преобразования. - person Wade Mueller; 06.01.2011
comment
@Chris Bos: когда я использую фильтр, все работает нормально, но возникает новая проблема, поскольку я использую BitmapData (currImg.width, currImg.width), сохраненное изображение маленькое (размер как элемент управления изображением), но мне нужно было сохранить изображение с исходным размером - person Sergey; 06.01.2011
comment
Метод draw принимает матрицу в качестве необязательного второго параметра, который вы должны использовать для масштабирования. Например. BitmapData.draw(currImg, новая матрица(2, 0, 0, 2)); //(Масштаб x2). Прочтите документацию по методу рисования, в ней объясняется, почему преобразования, примененные к источнику, не будут отображаться. (Он обрабатывает источник, как если бы это был библиотечный символ) - person Chris Bos; 06.01.2011
comment
@Chris Bos: BitmapData.draw(currImg, new Matrix(2, 0, 0, 2)) — масштабирование маленького изображения, а не моего оригинала, и сохранение изображения в пикселях. Я думаю, это потому, что мы используем (при создании BitmapData) currImg.width — означает ширину от элемента управления, но нам нужна исходная ширина изображения - person Sergey; 06.01.2011
comment
Да, размеры currImg соответствуют размеру элемента управления. Вам нужны contentHeight и contentWidth для фактических немасштабированных размеров. используйте эти значения для расчета того, что вам нужно масштабировать. Используйте параметр сглаживания метода рисования, чтобы уменьшить пикселизацию. Также попробуйте иметь скрытый элемент управления, который представляет собой фактические размеры загруженного изображения (необходимо добавить на сцену, но установите координаты -x, -y, чтобы он не был виден пользователю). Это сделает вас лучшим изображением для сохранения. - person Chris Bos; 06.01.2011
comment
@Chris Bos: хм, contentHeight и contentWidth возвращают не исходный размер изображения - person Sergey; 06.01.2011
comment
Странно, что такое свойства scaleX и scaleY в элементе управления Image? Умножьте это на ширину/высоту элемента управления изображением или contentWidth/Height. Вы должны где-то получить правильные значения. Также я бы предложил установить для свойства keepAspectRatio элемента управления изображением значение true. - person Chris Bos; 06.01.2011

Хорошо, это не лучшее решение, потому что я не знаю, почему оно работает, но если вы поместите контейнер вокруг изображения, сохраните результаты рисования, которые, похоже, работают.

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
    <fx:Script>
        <![CDATA[
            import mx.graphics.codec.JPEGEncoder;
            private var byteArr2:ByteArray;
            private var fileRef:FileReference = new FileReference(); 

            public function process():void
            {
                var ct:ColorTransform = new  ColorTransform();
                ct.redOffset = 99;
                ct.blueOffset = 11;
                ct.greenOffset = 22;
                currImg.transform.colorTransform = ct;
                callLater(toByteArray);
            }

            public function toByteArray():void
            {
                var data:BitmapData = new BitmapData(everything.width, everything.width);
                data.draw(everything);             
                var encod:JPEGEncoder = new JPEGEncoder(100);               
                byteArr2 = encod.encode(data);
            }
            public function saveFile():void 
            {  
                fileRef.save(byteArr2,"NewFileName1.jpg");
            } 
        ]]>
    </fx:Script>
    <mx:HBox>       
        <mx:VBox>           
            <!--<s:Button x="69" y="98" label="open" click="open()"/>-->
            <!--<s:Button label="show" click="show()"/> -->
            <s:Button label="process" click="process()"/>   
            <s:Button label="save" click="saveFile()"/> 
        </mx:VBox>
        <mx:Box id="everything">
            <mx:Image id="currImg" width="200" height="300" source="http://www.google.com/images/logos/ps_logo2.png"/>
        </mx:Box>
    </mx:HBox>
</s:Application>

Шон

person shaunhusain    schedule 05.01.2011
comment
Я до сих пор точно не уверен, но кажется, что вызов .colorTransform(rect,img) для растровых данных содержимого изображения также работает вместо его переноса, но по какой-то причине он появляется, когда преобразование цвета применяется к преобразование изображения каким-то образом оказывается в его собственном объекте, который не является дочерним элементом изображения (из документации он читает так, как будто он просто изменит пиксели bitmapData, но, похоже, это не так) - person shaunhusain; 06.01.2011