Top Banner
2015 Pebble Developer Retreat Pebble Graphics Matthew Hungerford, Firmware Engineer (Core Graphics)
61

#PDR15 - Pebble Graphics

Apr 12, 2017

Download

Technology

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: #PDR15 - Pebble Graphics

2015 Pebble Developer Retreat

Pebble Graphics

● Matthew Hungerford, Firmware Engineer (Core Graphics)

Page 2: #PDR15 - Pebble Graphics

Agenda• 1-Bit Past • Fonts • PNG Images • PDC/SVG Images • APNG Animated Images • Framebuffer Effects • Offscreen Rendering • Animations Vs. Power

Page 3: #PDR15 - Pebble Graphics

Glorious 1 Bit Past

Page 4: #PDR15 - Pebble Graphics

ABCWorking with fonts

Page 5: #PDR15 - Pebble Graphics

Bi-Layer Fonts• Outline provides contrast against varying background colors

• Create a font outline (fontforge)• Load font and font outline• Render both layers to get a bordered font

Page 6: #PDR15 - Pebble Graphics

Convert Hack-Font to Bi-Level

Page 7: #PDR15 - Pebble Graphics
Page 8: #PDR15 - Pebble Graphics
Page 9: #PDR15 - Pebble Graphics
Page 10: #PDR15 - Pebble Graphics
Page 11: #PDR15 - Pebble Graphics
Page 12: #PDR15 - Pebble Graphics

Generate Outline• Expand stroke (easier than outline)• Pen Type Rectangular• 250 width x 250 height

• File->Generate Font• Save as TTF as hack-outline.ttf

Page 13: #PDR15 - Pebble Graphics

Bi-Layer Font Setup//Time Displaychar time_string[] = "12:00";TextLayer* time_outline_layer = NULL;TextLayer* time_text_layer = NULL;static void window_load(Window *window) {... //Setup the time outline display time_outline_layer = text_layer_create(GRect(0, bounds.size.h / 2 - 30 / 2, bounds.size.w, 30)); text_layer_set_text(time_outline_layer, time_string); text_layer_set_font(time_outline_layer, fonts_load_custom_font( resource_get_handle(RESOURCE_ID_FONT_BOXY_OUTLINE_30))); text_layer_set_text_alignment(time_outline_layer, GTextAlignmentCenter); text_layer_set_background_color(time_outline_layer, GColorClear); text_layer_set_text_color(time_outline_layer, GColorBlack); layer_add_child(window_layer, text_layer_get_layer(time_outline_layer)); //Setup the time display time_text_layer = text_layer_create(GRect(0, bounds.size.h / 2 - 30 / 2, bounds.size.w, 30)); text_layer_set_text(time_text_layer, time_string); text_layer_set_font(time_text_layer, fonts_load_custom_font( resource_get_handle(RESOURCE_ID_FONT_BOXY_TEXT_30))); text_layer_set_text_alignment(time_text_layer, GTextAlignmentCenter); text_layer_set_background_color(time_text_layer, GColorClear); text_layer_set_text_color(time_text_layer, GColorWhite); layer_add_child(window_layer, text_layer_get_layer(time_text_layer));}

Page 14: #PDR15 - Pebble Graphics

Hack Time Demo

https://github.com/mhungerford/pebble_hack_font

• 2 Fonts in appinfo.json and resources/ −hack.ttf−hack-outline.ttf

• Should use same string for both layers

Page 15: #PDR15 - Pebble Graphics

Scrims• Fancy name for “Dark Overlays”• Used to draw focus to active content• Improves visibility by increasing contrasts between background and foreground material

Page 16: #PDR15 - Pebble Graphics

Scrims

• Pebble supports semi-transparent bitmaps• Use a 1x1 or 2x2 PNG for mask pattern• Use graphics_draw_bitmap for tiling• Render content on top of scrim

https://github.com/mhungerford/pebble_colorhex

Page 17: #PDR15 - Pebble Graphics

Scrim Font SetupGBitmap *mask = NULL;static void init() {} ... mask = gbitmap_create_with_resource(RESOURCE_ID_MASK);}static void digital_update_proc(Layer *layer, GContext *ctx) { GRect bounds = layer_get_bounds(layer); graphics_context_set_fill_color(ctx, GColorBlack); graphics_context_set_compositing_mode(ctx, GCompOpSet); GPoint box_point = grect_center_point(&bounds); // Size box to width of wday GSize box_size = graphics_text_layout_get_content_size(time_string, lcd_time_font, bounds, GTextOverflowModeWordWrap, GTextAlignmentCenter); box_size.w += 2; // Padding graphics_draw_bitmap_in_rect(ctx, mask, GRect(box_point.x - box_size.w / 2, bounds.origin.y, box_size.w, bounds.size.h)); graphics_context_set_text_color(ctx, GColorCyan); graphics_draw_text(ctx, time_string, lcd_time_font, GRect(bounds.origin.x + 2, bounds.origin.y - 2, bounds.size.w, bounds.size.h - 2), GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL);}

Page 18: #PDR15 - Pebble Graphics

Still ImagesWhy PNG8 is so great!

Page 19: #PDR15 - Pebble Graphics

PNG8• Palette format allowing from 1 to 256 colors, including varying levels of transparency (something GIF lacks).

• Filtered to improve compression• Compressed using DEFLATE (aka. zip)• Allows 1,2,4 and 8 bit depths (reducing memory by 8x, 4x, 2x and 1x respectively)

• Compression reduces images from 32.4KB to ~3-8KB

Page 20: #PDR15 - Pebble Graphics

Image Format Comparison• Both PNG and GIF support transparency

• GIF's transparency is 0% or 100%, there is no blending

• GIF selects 1 color to be fully transparent.

• PNG stores transparency per color

Page 21: #PDR15 - Pebble Graphics

• Free and Open Source• Available for Linux, OSX, Windows• Provides:−Scaling & cropping −adding text, borders and shapes−Convert JPG/BMP/GIF to PNG8−Color reduction and dithering

Command Line Image Processing (ImageMagick)

Page 22: #PDR15 - Pebble Graphics

Round Images

# Extend image and make everything outside radius 90 circle transparentconvert my.png -gravity center -extent '180x180' my.png convert -size 180x180 xc:none -fill my.png -draw "circle 90,90 90,1" my.png # Or# Extend image and use pebble hardware mask to make offscreen region transparentconvert my.png -gravity center -extent '180x180' my.png convert my.png -alpha set mask.png -compose DstIn -composite my.png

Page 23: #PDR15 - Pebble Graphics

Mimi Comic• Creative Commons Comic• Over 500 strips were created• Temp mascot for the EFF• Converted using imagemagick• Circle “Coins” for Pebble Time Round• Contrast tweaks for color• Background color detection and extending

• Best of baked in (like xkcd comic)• Additional Daily Comics on Timeline

Page 24: #PDR15 - Pebble Graphics

PDC (SVGs for Pebble)• Provides support for a vector graphics image format on Pebble• Converted from simple SVGs using svg2pdc.py• Allows vector features at runtime such as:−Scaling−Translating−Changing colors−Stretching

Page 25: #PDR15 - Pebble Graphics

Inkscape SVG tutorialBeing free doesn't make it easy!

Page 26: #PDR15 - Pebble Graphics

Download Vector Graphic from Pixabay.com (Creative Commons Art Site)

Page 27: #PDR15 - Pebble Graphics

Open SVG in Inkscape (Free Vector Software)

Page 28: #PDR15 - Pebble Graphics

Select object to remove from SVG

Page 29: #PDR15 - Pebble Graphics

Select object to remove from SVG

Page 30: #PDR15 - Pebble Graphics

Select object to remove from SVG

Page 31: #PDR15 - Pebble Graphics

File→Document Properties: Page : Resize Page to Drawing

Page 32: #PDR15 - Pebble Graphics

Object→Transform : Scale image to fit pebble

Page 33: #PDR15 - Pebble Graphics

Notice image now smaller than page

Page 34: #PDR15 - Pebble Graphics

File→Document Properties: Page : Resize Page to Drawing Again

Page 35: #PDR15 - Pebble Graphics

Edit→Select All : Object→Ungroup

Page 36: #PDR15 - Pebble Graphics

Object→Transform : Disable relative move and apply

Page 37: #PDR15 - Pebble Graphics

Save Image as Plain SVG

Page 38: #PDR15 - Pebble Graphics

SVG to PDC Conversion

git clone http://github.com/pebble-examples/cards-example

git clone http://github.com/pebble-examples/pdc-image

# Create or convert and SVG using Inkscape or Illustrator# Save test.svg in TinySVG 1.1 format with collapsed groups# Copy test.svg to cards-example/toolspython svg2pdc.py test.svg # Watch output values for negative or too large # Copy test.pdc to pdc-image/resources/commands# Update appinfo.json to use test.pdc for DRAW_COMMAND resource pebble build && pebble install --cloud

Page 39: #PDR15 - Pebble Graphics

SVG Robots On Pebble thanks to PDC

Page 40: #PDR15 - Pebble Graphics

Illustrator SVG tutorialTiny… Tiny… TinySVG

Page 41: #PDR15 - Pebble Graphics

Find cool vector art on pixabay.com

Page 42: #PDR15 - Pebble Graphics

Open SVG in illustrator

Page 43: #PDR15 - Pebble Graphics

Scale image to fit screen (<180x180)

Page 44: #PDR15 - Pebble Graphics

Edit→Select all, Object->Ungroup

Page 45: #PDR15 - Pebble Graphics

Object→Artboards→Fit to Selected Art

Page 46: #PDR15 - Pebble Graphics

File→SaveAs : SVG Tiny 1.1, decimal place 1, click “SVG Code”

Page 47: #PDR15 - Pebble Graphics

Verify SVG looks similar to this, no groups within groups, simple paths and basic elements, no translation matrix.Click “OK” to save.

Page 48: #PDR15 - Pebble Graphics

SVG to PDC Conversion

git clone http://github.com/pebble-examples/cards-example

git clone http://github.com/pebble-examples/pdc-image

# Create or convert and SVG using Inkscape or Illustrator# Save test.svg in TinySVG 1.1 format with collapsed groups# Copy test.svg to cards-example/toolspython svg2pdc.py test.svg # Watch output values for negative or too large # Copy test.pdc to pdc-image/resources/commands# Update appinfo.json to use test.pdc for DRAW_COMMAND resource pebble build && pebble install --cloud

Page 49: #PDR15 - Pebble Graphics

SVG Rocket on Watch

Page 50: #PDR15 - Pebble Graphics

Lively WatchfacesIf Time is always moving,

Why isn't your watchface?

Page 51: #PDR15 - Pebble Graphics

APNG (Animated PNG)Pros:• Created by Mozilla as an open, patent free alternative to GIF

• Now supported on iOS natively• Compression and memory benefits of PNG

• Additional frames only require the portion of image that changes

Cons:● APNGs are hard to generate● Very few tools support APNG● Most tools support GIFs

Page 52: #PDR15 - Pebble Graphics

PebbleGIF• Resizes and converts GIF to APNG• Automatically generates simple digital watchface using GIF

• Limited to 144x144 images

• Conversion done using gifsicle, gif2apng (modded) via wscript during build −Cherie is talking about waf later today

• gifsicle is an opensource gif optimizer/resizer• gif2apng modified source is included on repo

https://github.com/mhungerford/pebbleGIF

Page 53: #PDR15 - Pebble Graphics

PebbleGIF Examples

https://github.com/mhungerford/pebbleGIF

Page 54: #PDR15 - Pebble Graphics

Framebuffer EffectsPebble provides APIs to access both the app's main window as a framebuffer, as well as direct access to the pixels in Gbitmaps.

This access lets you go beyond the Pebble APIs for drawing, allowing you to push new graphical concepts into your apps.

https://github.com/mhungerford/pebble_fireworks

Page 55: #PDR15 - Pebble Graphics

Offscreen RenderingSimilar to framebuffer access, EXCEPT this can use pebble drawing commands to draw on offscreen buffers (GBitmap in this case).

This has the benefit that images can be composited over time, while still using Pebble's antialiased line drawing and other graphics functions.

Page 56: #PDR15 - Pebble Graphics

Text Overlays• With offscreen rendering, even text can be rendered to a GBitmap

• Since only bitmaps are currently drawn transparently, this can be used to render text, modify the alpha values, and placed back on the screen in transparent form.

https://github.com/mhungerford/pebble_offscreen_rendering_text_demo

Page 57: #PDR15 - Pebble Graphics

Offscreen Rendering Code static void offscreen_layer_update(Layer* layer, GContext *ctx) { GRect bounds = layer_get_bounds(layer); // Capture the graphics context framebuffer GBitmap *framebuffer = graphics_capture_frame_buffer(ctx); // backup old framebuffer format data uint8_t *orig_addr = gbitmap_get_data(framebuffer); GBitmapFormat orig_format = gbitmap_get_format(framebuffer); uint16_t orig_stride = gbitmap_get_bytes_per_row(framebuffer); // Release the framebuffer now that we are free to modify it graphics_release_frame_buffer(ctx, framebuffer); // Create the offscreen framebuffer GBitmap

GRect offscreen_bounds = GRect(0, 0, 80, 32); GBitmap *offscreen_bitmap = gbitmap_create_blank(offscreen_bounds.size, GBitmapFormat8Bit); // replace screen bitmap with our offscreen render bitmap gbitmap_set_data(framebuffer, gbitmap_get_data(offscreen_bitmap), gbitmap_get_format(offscreen_bitmap),

gbitmap_get_bytes_per_row(offscreen_bitmap), false); // Draw to the offscreen bitmap graphics_draw_text(ctx, "Hello", font, offscreen_bounds, GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL); // Make the offscreen_bitmap transparent (user provided function) bitmap_make_transparent(offscreen_bitmap); // restore original context bitmap gbitmap_set_data(framebuffer, orig_addr, orig_format, orig_stride, false); // draw the offscreen bitmap rotated 180 deg to the screen to have rotated transparent text graphics_draw_rotated_bitmap(ctx, offscreen_bitmap, grect_center_point(&offscreen_bounds),

TRIG_MAX_ANGLE / 2, grect_center_point(&bounds)); gbitmap_destroy(offscreen_bitmap);}

Page 58: #PDR15 - Pebble Graphics

Animations Vs. PowerWith great power (usage) comes great responsibility.

Page 59: #PDR15 - Pebble Graphics

Flick to Animate

https://github.com/mhungerford/pebble_glancing_demo

• Subscribe to the tap-service• When user flicks wrist for backlight, triggers animations.• Very power conservative, as animations are intentionally triggered.

• Decent user experience, watch only animates when user consciously decides via flick.

Page 60: #PDR15 - Pebble Graphics

Glancing Demo

https://github.com/mhungerford/pebble_glancing_demo

• Allows animations without using flick (tap service)• Simple library modeled after accel_data_service• Similar to gestures, recognizes when watch goes from hanging downward to being looked at, or wrist rotation away and back

• Triggers callback for glancing state that can be used for animations, seconds hands, unpausing game, or data refresh from web.

• Can control backlight

Page 61: #PDR15 - Pebble Graphics

Questions?