Privacy Policy ยท Cookie Policy
  • Home
  • Tutorials
  • Get the SDK
  • Guides
  • Documentation
  • Examples
  • Community
  • Blog
  • More
  • Tutorials
  • Learn C Basics
  • Create a C Watchface
  • Create a JS Watchapp
  • Add More Features
  • Go Beyond
  • PebbleKit Android Tutorial
  • PebbleKit iOS Tutorial
  • Learn C Basics
  • Learning C for the Pebble SDK
  • A Simple C Program
  • Hello, Pebble!
  • More C Concepts
  • Create a C Watchface
  • Build Your Own Watchface
  • Customize Your Watchface
  • Adding Content From The Web
  • Create a JS Watchapp
  • Build A Watchapp with Pebble.js
  • Expanded Weather Forecasts
  • Adding More Details
  • Add More Features
  • Add a Date View
  • Add a Battery Meter
  • Add Connection Alerts
  • Go Beyond
  • Vector Animations
  • PebbleKit Android Tutorial
  • Integrating with Android
  • Controlling Apps From Pebble
  • Rock, Paper, Scissors with Pebble
  • PebbleKit iOS Tutorial
  • Integrating with iOS
  • Controlling Apps From Pebble
  • Rock, Paper, Scissors with Pebble
  • Guides
  • App Resources
  • Appstore Publishing
  • Best Practices
  • Communication
  • Debugging
  • Design and Interaction
  • Events and Services
  • Graphics and Animations
  • Migrating Older Apps
  • Pebble Packages
  • Pebble Timeline
  • Smartstraps
  • Tools and Resources
  • User Interfaces
  • App Resources
  • Animated Images
  • App Assets
  • Converting SVG to PDC
  • Fonts
  • Images
  • Pebble Draw Command File Format
  • Platform-specific Resources
  • Raw Data Files
  • System Fonts
  • Appstore Publishing
  • Appstore Analytics
  • Appstore Assets
  • Preparing a Submission
  • Publishing an App
  • iOS App Whitelisting
  • Best Practices
  • Building for Every Pebble
  • Conserving Battery Life
  • Modular App Architecture
  • Communication
  • Advanced Communication
  • Datalogging
  • Sending and Receiving Data
  • PebbleKit Android
  • PebbleKit iOS
  • PebbleKit JS
  • Sports API
  • Debugging
  • Common Runtime Errors
  • Common Syntax Errors
  • Debugging with App Logs
  • Debugging with GDB
  • Design and Interaction
  • Benefits of Design Guidelines
  • Core Experience Design
  • Example Implementations
  • Round App Design
  • One Click Actions
  • Recommended Guidelines and Patterns
  • Events and Services
  • Accelerometer
  • Background Worker
  • Buttons
  • Compass
  • Dictation
  • Event Services
  • Pebble Health
  • Persistent Storage
  • Wakeups
  • Graphics and Animations
  • Animations
  • Drawing Primitives, Images and Text
  • Framebuffer Graphics
  • Vector Graphics
  • Migrating Older Apps
  • SDK 3.x on Aplite Migration Guide
  • SDK 3.x Migration Guide
  • SDK 4.x Migration Guide
  • SDK 2.x Migration Guide
  • PebbleKit iOS 3.0 Migration Guide
  • Pebble Packages
  • Creating Pebble Packages
  • Using Pebble Packages
  • Pebble Timeline
  • Creating Pins
  • Service Architecture
  • Managing Subscriptions
  • Libraries for Pushing Pins
  • Public Web API
  • Smartstraps
  • Hardware Specification
  • Protocol Specification
  • Talking To Pebble
  • Talking To Smartstraps
  • Tools and Resources
  • App Metadata
  • CloudPebble
  • Color Picker Tool
  • Developer Connection
  • Hardware Information
  • Internationalization
  • Command Line Tool
  • User Interfaces
  • App Configuration
  • App Exit Reason
  • AppGlance C API
  • AppGlance in PebbleKit JS
  • AppGlance REST API
  • Layers
  • Round App UI
  • Unobstructed Area
  • Documentation
  • Pebble C
  • Pebble JavaScript API (beta)
  • PebbleKit JavaScript
  • PebbleKit iOS
  • PebbleKit Android
  • Pebble C
  • Pebble JavaScript API (beta)
  • PebbleKit JavaScript
  • PebbleKit iOS
  • PebbleKit Android
  • Community
  • Events
  • Online Communities
  • Example Apps
  • Tools
  • Libraries
  • Events
  • Developer Retreat 2014
  • Developer Retreat 2015
  • Example Apps
  • Hello
  • Caltrain
  • HeroBoard
  • Multi Timer
  • Resistor Time
  • Tools
  • App Message Bridge
  • Appstore Badge Generator
  • GPath.svg
  • pBuild Travis CI Build Tool
  • Sublime Text Plugin
  • Watchface Generator
  • Watch Status
  • Libraries
  • Color Selector
  • Custom Status Bar for Pebble
  • EffectLayer
  • GBitmap Colour Palette Manipulator
  • Java Pebble Timeline
  • JS Message Queue
  • Pebble Timeline API for DotNet (C#)
  • Pebble API PHP
  • PebbleTimeline API Ruby
  • PHPebbleTimeline
  • PinPusher
  • pypebbleapi
  • Simple Dithering Library
  • T3 Keyboard
  • ToastLayer Library
  • More
  • Examples
  • App Inspiration
  • Contact
  • Build Tools
pebble
  • Tutorials
  • Get the SDK
  • Guides
  • Documentation
  • Examples
  • Community
  • Blog
  • More
Privacy
Cookies
Publish

Guides

  • Table of Contents
  • App Resources
    • Animated Images
    • App Assets
    • Converting SVG to PDC
    • Fonts
    • Images
    • Pebble Draw Command File Format
    • Platform-specific Resources
    • Raw Data Files
    • System Fonts
  • Appstore Publishing
  • Best Practices
  • Communication
  • Debugging
  • Design and Interaction
  • Events and Services
  • Graphics and Animations
  • Migrating Older Apps
  • Pebble Packages
  • Pebble Timeline
  • Rocky.js
  • Smartstraps
  • Tools and Resources
  • User Interfaces

Animated Images

This page contains some instructions that are different if you're using CloudPebble or if you're using the SDK locally on your computer.

Select whether you're using CloudPebble or the SDK below to show the relevant instructions!

CloudPebble

SDK

Showing instructions for CloudPebble. Not using CloudPebble?

Showing instructions for the SDK. Using CloudPebble?

The Pebble SDK allows animated images to be played inside an app using the GBitmapSequence API, which takes APNG images as input files. APNG files are similar to well-known .gif files, which are not supported directly but can be converted to APNG.

A similar effect can be achieved with multiple image resources, a BitmapLayer and an AppTimer, but would require a lot more code. The GBitmapSequence API handles the reading, decompression, and frame duration/count automatically.

Converting GIF to APNG

A .gif file can be converted to the APNG .png format with gif2apng and the -z0 flag:

./gif2apng -z0 animation.gif

Note: The file extension must be .png, not .apng.

Adding an APNG

Include the APNG file in the resources array in package.json as a raw resource:

"resources": {
  "media": [
    {
      "type":"raw",
      "name":"ANIMATION",
      "file":"images/animation.png"
    }
  ]
}

To add the APNG file as a raw resource, click 'Add New' in the Resources section of the sidebar, and set the 'Resource Type' as 'raw binary blob'.

Displaying APNG Frames

The GBitmapSequence will use a GBitmap as a container and update its contents each time a new frame is read from the APNG file. This means that the first step is to create a blank GBitmap to be this container.

Declare file-scope variables to hold the data:

static GBitmapSequence *s_sequence;
static GBitmap *s_bitmap;

Load the APNG from resources into the GBitmapSequence variable, and use the frame size to create the blank GBitmap frame container:

// Create sequence
s_sequence = gbitmap_sequence_create_with_resource(RESOURCE_ID_ANIMATION);

// Create blank GBitmap using APNG frame size
GSize frame_size = gbitmap_sequence_get_bitmap_size(s_sequence);
s_bitmap = gbitmap_create_blank(frame_size, GBitmapFormat8Bit);

Once the app is ready to begin playing the animated image, advance each frame using an AppTimer until the end of the sequence is reached. Loading the next APNG frame is handled for you and written to the container GBitmap.

Declare a BitmapLayer variable to display the current frame, and set it up as described under Displaying An Image.

static BitmapLayer *s_bitmap_layer;

Create the callback to be used when the AppTimer has elapsed, and the next frame should be displayed. This will occur in a loop until there are no more frames, and gbitmap_sequence_update_bitmap_next_frame() returns false:

static void timer_handler(void *context) {
  uint32_t next_delay;

  // Advance to the next APNG frame, and get the delay for this frame
  if(gbitmap_sequence_update_bitmap_next_frame(s_sequence, s_bitmap, &next_delay)) {
    // Set the new frame into the BitmapLayer
    bitmap_layer_set_bitmap(s_bitmap_layer, s_bitmap);
    layer_mark_dirty(bitmap_layer_get_layer(s_bitmap_layer));

    // Timer for that frame's delay
    app_timer_register(next_delay, timer_handler, NULL);
  }
}

When appropriate, schedule the first frame advance with an AppTimer:

uint32_t first_delay_ms = 10;

// Schedule a timer to advance the first frame
app_timer_register(first_delay_ms, timer_handler, NULL);

When the app exits or the resource is no longer required, destroy the GBitmapSequence and the container GBitmap:

gbitmap_sequence_destroy(s_sequence);
gbitmap_destroy(s_bitmap);

Overview

  • Converting GIF to APNG
  • Adding an APNG
  • Displaying APNG Frames