четверг, 15 октября 2009 г.

Blackberry GIF Rendering

Как известно, рендеринг анимированной гифки в BlackBerry отсутствует. Решение - костыль, рисующий кадр за кадром в отдельном потоке, представленный RIM в базе знаний .
Единственная проблема - алгоритм не поддерживает оптимизированные gif.

Небольшая модификация кода от RIM позволяет эту проблему решить
Рисуем кадр-за кадром на отдельном битмапе, который впоследствии отображается на экране.

...
private Bitmap background;
...
 protected void paint(Graphics graphics) {
//Optimized gif support: draw frame-by-frame on the background layer
  Graphics g = new Graphics(background);
  g.drawImage(_image.getFrameLeft(_currentFrame), _image
    .getFrameTop(_currentFrame), _image
    .getFrameWidth(_currentFrame), _image
    .getFrameHeight(_currentFrame), _image, _currentFrame, 0, 0);
  graphics.drawBitmap(0, 0, background.getWidth(),
    background.getHeight(), background, 0, 0);

 }

Весь код:
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.GIFEncodedImage;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.BitmapField;

//A field that displays an animated GIF.

public class AnimatedGIFField extends BitmapField {
 private GIFEncodedImage _image; // The image to draw.
 private int _currentFrame; // The current frame in
 // the animation sequence.
 private int _width; // The width of the image
 // (background frame).
 private int _height; // The height of the image
 // (background frame).
 private AnimatorThread _animatorThread;
 private Bitmap background;

 public AnimatedGIFField(GIFEncodedImage image) {
  this(image, 0);
 }

 public AnimatedGIFField(GIFEncodedImage image, long style) {
  // Call super to setup the field with the specified style.
  // The image is passed in as well for the field to
  // configure its required size.
  super(image.getBitmap(), style);

  // Store the image and it's dimensions.
  _image = image;
  _width = image.getWidth();
  _height = image.getHeight();
  background = image.getBitmap();
  // Start the animation thread.
  _animatorThread = new AnimatorThread(this);
  _animatorThread.start();
 }

 protected void paint(Graphics graphics) {
//Optimized gif support: draw frame-by-frame on the background layer
  Graphics g = new Graphics(background);
  g.drawImage(_image.getFrameLeft(_currentFrame), _image
    .getFrameTop(_currentFrame), _image
    .getFrameWidth(_currentFrame), _image
    .getFrameHeight(_currentFrame), _image, _currentFrame, 0, 0);
  graphics.drawBitmap(0, 0, background.getWidth(),
    background.getHeight(), background, 0, 0);

 }

 // Stop the animation thread when the screen the field is on is
 // popped off of the display stack.
 protected void onUndisplay() {
  _animatorThread.stop();
  super.onUndisplay();
 }

 // A thread to handle the animation.
 private class AnimatorThread extends Thread {
  private AnimatedGIFField _theField;
  private boolean _keepGoing = true;
  private int _totalFrames; // The total number of
  // frames in the image.
  private int _loopCount; // The number of times the
  // animation has looped (completed).
  private int _totalLoops; // The number of times the animation should

  // loop (set in the image).

  public AnimatorThread(AnimatedGIFField theField) {
   _theField = theField;
   _totalFrames = _image.getFrameCount();
   _totalLoops = _image.getIterations();

  }

  public synchronized void stop() {
   _keepGoing = false;
  }

  public void run() {
   while (_keepGoing) {
    // Invalidate the field so that it is redrawn.
    UiApplication.getUiApplication().invokeAndWait(new Runnable() {
     public void run() {
      _theField.invalidate();
     }
    });

    try {
     // Sleep for the current frame delay before
     // the next frame is drawn.
     sleep(_image.getFrameDelay(_currentFrame) * 10);
    } catch (InterruptedException iex) {
    } // Couldn't sleep.

    // Increment the frame.
    ++_currentFrame;

    if (_currentFrame == _totalFrames) {
     // Reset back to frame 0 if we have reached the end.
     _currentFrame = 0;

     ++_loopCount;

     // Check if the animation should continue.
     if (_loopCount == _totalLoops) {
      _keepGoing = false;
     }
    }
   }
  }
 }
}

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

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