Кэширование растрового изображения

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

Хорошей оптимизации можно достичь с помощью функции кэширования растровых изображений. Эта функция кэширует векторный объект, визуализирует его как растровое изображение при внутренней обработке и использует это растровое изображение для визуализации. Она позволяет получить огромное повышение производительности визуализации, однако может требовать использования значительного объема памяти. Используйте функцию кэширования растрового изображения для сложного векторного содержимого, такого как сложные градиенты или текст.

Производительность повышается, если включить кэширование растровых изображений для анимированного объекта со сложной векторной графикой, такого как текст или градиенты. Однако, если кэширование растрового изображения включено для экранного объекта, такого как фрагмент ролика, для которого воспроизводится временная шкала, получается противоположный результат. В каждом кадре среда выполнения должна обновлять кэшированное растровое изображение, а затем перерисовывать его на экране, а для этого требуется большое число циклов ЦП. Функция кэширования растровых изображений способствует оптимизации, только если кэшированное растровое создается единожды и более не обновляется.

Если включить кэширование растровых изображений для спрайтов, при их перемещении среда выполнения не будет повторно генерировать кэшированные растровые изображения. Изменение свойств x и y объекта не требует повторной генерации. Однако, если объекты будут вращаться, масштабироваться или будет меняться альфа-коэффициент, среда выполнения будет повторного генерировать кэшированные растровые изображения, что снизит производительность.

Примечание. Свойство DisplayObject.cacheAsBitmapMatrix , доступное в среде AIR и инструменте Packager for iPhone, не подвержено этим ограничениям. Используя свойство cacheAsBitmapMatrix , можно поворачивать, масштабировать, наклонять и изменять альфа-коэффициент без повторной регенерации растровых изображений.

Кэшированные растровые изображения могут занимать больше памяти, чем обычный экземпляр фрагмента ролика. Например, если фрагмент ролика в рабочей области имеет размер 250 x 250 пикселов, при кэшировании он занимает около 250 КБ (по сравнению с 1 КБ в некэшированном состоянии).

В следующем примере показан объект Sprite, содержащий изображение яблока. Следующий класс соединен с символом яблока.

package org.bytearray.bitmap 
{     
    import flash.display.Sprite; 
    import flash.events.Event; 
     
    public class Apple extends Sprite 
    { 
        private var destinationX:Number; 
        private var destinationY:Number; 
         
        public function Apple () 
        { 
            addEventListener(Event.ADDED_TO_STAGE,activation); 
            addEventListener(Event.REMOVED_FROM_STAGE,deactivation);     
        } 
         
        private function activation(e:Event):void  
        { 
            initPos();     
            addEventListener (Event.ENTER_FRAME,handleMovement);     
        } 
         
        private function deactivation(e:Event):void  
        { 
            removeEventListener(Event.ENTER_FRAME,handleMovement);     
        } 
         
        private function initPos():void 
        { 
            destinationX = Math.random()*(stage.stageWidth - (width>>1)); 
            destinationY = Math.random()*(stage.stageHeight - (height>>1)); 
        } 
         
        private function handleMovement(e:Event):void  
        { 
            x -= (x - destinationX)*.5; 
            y -= (y - destinationY)*.5; 
             
            if (Math.abs(x - destinationX) < 1 && Math.abs(y - destinationY) < 1) 
                initPos(); 
        } 
    } 
}

В этом коде вместо класса MovieClip используется класс Sprite, поскольку временная шкала не требуется для каждого яблока. Для получения наиболее оптимальной производительности по возможности используйте самый легковесный объект. Затем экземпляры класса создаются с помощью следующего кода.

import org.bytearray.bitmap.Apple; 
 
stage.addEventListener(MouseEvent.CLICK,createApples); 
stage.addEventListener(KeyboardEvent.KEY_DOWN,cacheApples); 
 
const MAX_NUM:int = 100; 
var apple:Apple; 
var holder:Sprite = new Sprite(); 
 
addChild(holder); 
 
function createApples(e:MouseEvent):void 
{ 
    for (var i:int = 0; i< MAX_NUM; i++) 
    { 
        apple = new Apple(); 
         
        holder.addChild(apple); 
    } 
} 
 
function cacheApples(e:KeyboardEvent):void 
{ 
    if (e.keyCode == 67) 
    { 
        var lng:int = holder.numChildren; 
         
        for (var i:int = 0; i < lng; i++) 
        { 
            apple = holder.getChildAt (i) as Apple; 
             
            apple.cacheAsBitmap = Boolean(!apple.cacheAsBitmap); 
        } 
    } 
}

Когда пользователь нажимает кнопку мыши, изображения яблок создаются без кэширования. Когда пользователь нажимает клавишу C (код клавиши 67), векторы яблок кэшируются в качестве растровых изображений и показываются на экране. Этот прием позволяет значительно повысить производительность визуализации как в настольных системах, так и в мобильных устройствах с низкой производительностью процессора.

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

Объект и растровое изображение его поверхности, сохраненное в памяти

Flash Player 10.1 и AIR 2.5 оптимизируют использование памяти за счет подхода, описанного в разделе « Фильтры и динамическая выгрузка растровых изображений ». Если кэшированный экранный объект скрыт или находится вне экрана, а его растровое изображение, сохраненное в памяти, какое-то время не используется, оно удаляется из памяти.

Примечание. Если для свойства opaqueBackground экранного объекта задан определенный цвет, в среде выполнения экранный объект считается непрозрачным. Свойство cacheAsBitmap заставляет среду выполнения создавать в памяти непрозрачное 32-битное растровое изображение. Для альфа-канала задано значение 0xFF, что позволяет повысить производительность, поскольку для рисования объекта на экране не требуется прозрачность. Предотвращение наложения альфа-канала позволяет выполнить визуализацию еще быстрее. Если текущая глубина экрана ограничена 16 битами, растровое изображение хранится в памяти как 16-битное изображение. Свойство opaqueBackground напрямую не вызывает кэширование растровых изображений.

В целях экономии памяти используйте свойство cacheAsBitmap и активируйте его для каждого экранного объекта, а не контейнера. При активации кэширования растрового изображения в контейнере конечное изображение занимает гораздо больше памяти, поскольку прозрачное растровое изображение создается с размерами 211 x 279 пикселов. Изображение занимает около 229 КБ памяти:

Полноразмерное изображение
Активация кэширования растрового изображения в контейнере

Кроме того, если какое-либо яблоко в кадре будет двигаться, кэширование контейнера приведет к обновлению в памяти растрового изображения целиком. Активация кэширования растрового изображения в отдельных экземплярах приводит к кэшированию шести поверхностей размером 7 КБ в памяти, для этого требуется всего 42 КБ памяти:

Полноразмерное изображение
Активация кэширования растрового изображения в экземплярах

При доступе к каждому экземпляру яблока через список отображения и вызове метода getChildAt() ссылки сохраняются в объекте Vector для упрощения доступа.

import org.bytearray.bitmap.Apple; 
 
stage.addEventListener(KeyboardEvent.KEY_DOWN, cacheApples); 
 
const MAX_NUM:int = 200; 
var apple:Apple; 
var holder:Sprite = new Sprite(); 
 
addChild(holder); 
 
var holderVector:Vector.<Apple> = new Vector.<Apple>(MAX_NUM, true); 
 
for (var i:int = 0; i< MAX_NUM; i++) 
{ 
    apple = new Apple(); 
     
    holder.addChild(apple); 
     
    holderVector[i] = apple; 
} 
 
function cacheApples(e:KeyboardEvent):void 
{ 
    if (e.keyCode == 67) 
    { 
        var lng:int = holderVector.length 
         
        for (var i:int = 0; i < lng; i++) 
        { 
            apple = holderVector[i]; 
             
            apple.cacheAsBitmap = Boolean(!apple.cacheAsBitmap); 
        } 
    } 
}

Помните, что кэширование растровых изображений ускоряет визуализацию, только если содержимое не вращается, не масштабируется и не изменяется в каждом кадре. Однако для любого преобразования, отличного от переноса вдоль осей X и Y, качество визуализации не улучшается. В этих случаях проигрыватель Flash Player обновляет копию кэшированного растрового изображения при каждом преобразовании экранного объекта. Обновление кэшированной копии может приводить к увеличению загрузки ЦП, снижению производительности и повышению уровня использования аккумулятора. И снова это ограничение не распространяется на свойство cacheAsBitmapMatrix , доступное в среде AIR или инструменте Packager for iPhone.

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

private function handleMovement(e:Event):void  
{ 
        alpha = Math.random(); 
        x -= (x - destinationX)*.5; 
        y -= (y - destinationY)*.5; 
             
        if (Math.abs(x - destinationX) < 1 && Math.abs(y - destinationY) < 1) 
            initPos(); 
}

Использование кэширования растрового изображение влечет снижение производительности. При изменении альфа-коэффициента среда выполнения обновляет кэшированное растровое изображение в памяти.

Фильтры зависят от растровых изображений, обновляемых при перемещении точки воспроизведения кэшированного фрагмента ролика. Поэтому при использовании фильтра для свойства cacheAsBitmap автоматически задается значение true . Ниже представлен пример с анимированным фрагментом ролика.

Фрагмент ролика с анимацией

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

Фрагмент ролика с анимацией и фильтром «Тень»

В результате, если временная шкала сдвигается (т. е. клип воспроизводится), растровое изображение необходимо генерировать повторно. Кроме того, его требуется повторно генерировать в каждом случае, когда содержимое изменяется любым образом, кроме простого перемещения по осям x и y. Среда выполнения должна перерисовывать растровое изображение в каждом кадре, что приводит к использованию дополнительных ресурсов ЦП, снижению производительности и повышению уровня использования аккумулятора.

Пол Трани (Paul Trani) приводит примеры использования Flash Professional и ActionScript для оптимизации графики с использованием растровых изображений в следующих обучающих видеороликах: