SlideShare a Scribd company logo
1 of 64
Download to read offline
GRAPHICS 
MATT & HEIKO – DEVELOPER EXPERIENCE ENGINEERS 
ON TWITTER AS @MTHUNGERFORD & @HBEHRENS
THE DISPLAY 
144x168px @ 175 DPI 
black & white only 
25+ FPS
CONTENT 
A Pixel’s Journey 
Dithering 
Accessing the Frame Buffer
A PIXEL’S 
JOURNEY
LAYER STACK 
Layers are added to the 
layer_stack from back to front 
starting from the window layer. 
! 
Layers are then rendered from 
back to front into the application 
frame buffer. 
Window
THE COMPOSITOR 
Example of a non-fullscreen application (144x152): 
Application 
frame buffer 
Compositor 
frame buffer 
Final 
display
GRAPHICS APIS 
static void custom_update_proc(Layer *layer, GContext *ctx); 
Layer-equivalents working directly on GContext 
graphics_draw_text, graphics_draw_bitmap_in_rect 
Drawings vector graphics 
gpath_draw_filled, gpath_draw_outline 
Drawings raster graphics 
graphics_draw_pixel, graphics_draw_line 
graphics_draw_circle, graphics_fill_circle, 
graphics_draw_rect, graphics_draw_round_rect, graphics_fill_rect 
Animate graphics 
app_timer_register, app_timer_reschedule, app_timer_cancel 
Animation, PropertyAnimation
Q&A 
source: https://www.youtube.com/watch?v=Ej2ELEK-C3Q Where To?
GRAPHICS APIS 
static void custom_update_proc(Layer *layer, GContext *ctx); 
Layer-equivalents working directly on GContext 
graphics_draw_text, graphics_draw_bitmap_in_rect 
Drawings vector graphics 
gpath_draw_filled, gpath_draw_outline 
Drawings 
raster graphics 
graphics_draw_pixel, graphics_draw_line 
graphics_draw_circle, graphics_fill_circle, 
graphics_draw_rect, graphics_draw_round_rect, graphics_fill_rect 
Animate graphics 
app_timer_register, app_timer_reschedule, app_timer_cancel 
Animation, PropertyAnimation
Drawings advanced raster graphics 
graphics_capture_frame_buffer, graphics_release_frame_buffer 
Doing dithering at runtime
DITHERING
Dither is an intentionally applied form of noise used to 
randomize quantization error, preventing large-scale 
patterns such as color banding in images. 
http://en.wikipedia.org/wiki/Dither 
256 shades of gray 
16 shades of gray + nearest color 
16 shades of gray + random noise 
16 shades of gray + ordered dithering
256 shades of gray 
16 SHADES OF GRAY 
16 shades of gray + nearest color 
16 shades of gray + random noise 
16 shades of gray + ordered dithering 
BLACK AND WHITE 
black & white + nearest color 
black & white + noise 
black & white + ordered dithering
original ordered dithering Floyd-Steinberg 
dithering 
nearest color
FLOYD-STEINBERG DITHERING 
for each y from top to bottom 
for each x from left to right 
oldpixel := pixel[x][y] 
newpixel := find_closest_palette_color(oldpixel) 
pixel[x][y] := newpixel 
quant_error := oldpixel - newpixel 
pixel[x+1][y ] := pixel[x+1][y ] + quant_error * 7/16 
pixel[x-1][y+1] := pixel[x-1][y+1] + quant_error * 3/16 
pixel[x ][y+1] := pixel[x ][y+1] + quant_error * 5/16 
pixel[x+1][y+1] := pixel[x+1][y+1] + quant_error * 1/16 
ORDERED DITHERING (BAYER MATRIX) 
threshold_map_4x4 = 
foreach y 
foreach x 
oldpixel := pixel[x][y] + threshold_map_4x4[x mod 4][y mod 4] 
newpixel := find_closest_palette_color(oldpixel) 
pixel[x][y] := newpixel
source: Joel Yliluoma’s dithering page - http://bisqwit.iki.fi/story/howto/dither/jy/ original from PSX game “Chrono Cross”
source: Joel Yliluoma’s dithering page - http://bisqwit.iki.fi/story/howto/dither/jy/ nearest neighbor to 12 colors
source: Joel Yliluoma’s dithering page - http://bisqwit.iki.fi/story/howto/dither/jy/ Floyd-Steinberg to 12 colors
OFFLINE 
DITHERING
BETTER BITMAPS (GIMP/PHOTOSHOP) 
Resize to desired size (<144x168) using sinc filter 
Convert image to grayscale 
Modify brightness/contrast to sharpen image 
Posterize to 3 colors (if dithering to gray_50) or 2 
colors for black and white. 
Undo-Redo brightness/contrast & posterize till 
desired effect 
Convert image to black and white with ordered 
(positional) dithering
Better Bitmaps (GIMP/Photoshop) 
Open Original Image in the GIMP/Photoshop
Better Bitmaps (GIMP/Photoshop) 
Resize: Image -> Scale Image
Better Bitmaps (GIMP/Photoshop) 
Resize to desired size (<144x168) using sinc filter
Better Bitmaps (GIMP/Photoshop) 
Grayscale: Image -> Mode -> Grayscale
Better Bitmaps (GIMP/Photoshop) 
Brightness-Contrast: Colors -> Brightness-Contrast
Better Bitmaps (GIMP/Photoshop) 
Slide contrast to right to remove colors and balance with brightness
Better Bitmaps (GIMP/Photoshop) 
Posterize: Colors -> Posterize
Better Bitmaps (GIMP/Photoshop) 
Posterize: Select 3 colors (2 for black & white only). 3rd color is Gray.
Better Bitmaps (GIMP/Photoshop) 
Convert to 1-bit (b&w): Image -> Mode -> Indexed
Better Bitmaps (GIMP/Photoshop) 
Select b&w, choose dithering Positioned (Ordered) for dithered gray
Better Bitmaps (GIMP/Photoshop) 
Final Product: Robot with dithered gray_50
BETTER BITMAPS (IMAGEMAGICK) 
convert orig.png 
-adaptive-resize '144x168>' 
-fill '#FFFFFF00' -opaque none 
-type Grayscale -colorspace Gray 
-black-threshold 30% -white-threshold 70% 
-ordered-dither 2x1 
-colors 2 -depth 1 
-define png:compression-level=9 
-define png:compression-strategy=0 
-define png:exclude-chunk=all 
new.png
DITHERED ANIMATIONS (APNG) 
ImageMagick scripting 
! 
Ordered dithering (gray_50) 
! 
(a)PNG compression for 200 frames 
! 
Resource loading and drawing at high FPS 
(10 FPS in this example)
RUNTIME 
DITHERING
50% GRAY
PRE-DITHERED 
FLOYD 
STEINBERG 
ORDERED 
DITHERING
PRE-DITHERED 
AT RUNTIME
PRE-DITHERED 
AT RUNTIME
PRE-DITHERED 
AT RUNTIME
PRE-DITHERED 
AT RUNTIME
PRE-DITHERED 
AT RUNTIME
50% GRAY
PRE-DITHERED 
FLOYD 
STEINBERG 
ORDERED 
DITHERING
source: Joel Yliluoma’s dithering page - http://bisqwit.iki.fi/story/howto/dither/jy/ reduction to 18 colors
IMPLEMENT 
DITHERING 
AT RUNTIME
ORDERED DITHERING (BAYER MATRIX) 
threshold_map_4x4 = 
foreach y 
foreach x 
oldpixel := pixel[x][y] + threshold_map_4x4[x mod 4][y mod 4] 
newpixel := find_closest_palette_color(oldpixel) 
pixel[x][y] := newpixel 
ORDERED DITHERING BLACK & WHITE 
foreach y 
foreach x 
newpixel := pixel[x][y] > threshold_map_8x8[x mod 8][y mod 8] ? white : black; 
pixel[x][y] := newpixel
ORDERED DITHERING BLACK & WHITE 
foreach y 
foreach x 
newpixel := pixel[x][y] > threshold_map_8x8[x mod 8][y mod 8] ? white : black; 
pixel[x][y] := newpixel 
IMPLEMENTED IN C 
// Bayer matrix for ordered dithering 
static const uint8_t ditherMatrix[8][8] = { 
{ 0*4, 32*4, 8*4, 40*4, 2*4, 34*4, 10*4, 42*4}, 
{48*4, 16*4, 56*4, 24*4, 50*4, 18*4, 58*4, 26*4}, 
{12*4, 44*4, 4*4, 36*4, 14*4, 46*4, 6*4, 38*4}, 
{60*4, 28*4, 52*4, 20*4, 62*4, 30*4, 54*4, 22*4}, 
{ 3*4, 35*4, 11*4, 43*4, 1*4, 33*4, 9*4, 41*4}, 
{51*4, 19*4, 59*4, 27*4, 49*4, 17*4, 57*4, 25*4}, 
{15*4, 47*4, 7*4, 39*4, 13*4, 45*4, 5*4, 37*4}, 
{63*4, 31*4, 55*4, 23*4, 61*4, 29*4, 53*4, 21*4} 
}; 
! 
static GColor color_for_gray(int16_t x, int16_t y, uint8_t gray) { 
return gray > ditherMatrix[y % 8][x % 8] ? GColorWhite : GColorBlack; 
}
DOING LIVE DITHERING 
gray_top 
gray_bottom 
static GColor color_for_gray(int16_t x, int16_t y, uint8_t gray); 
! 
static void update_proc_draw_pixel(Layer *layer, GContext *ctx) { 
! 
! 
! 
} 
const int16_t h = window_size.h; 
for (int16_t y = 0; y < h; y++) { 
! 
! 
! 
! 
} 
uint8_t row_gray = (uint8_t)((gray_top * (h - y) + y * gray_bottom) / h);
AVOIDING FLOATS frac = 0.0 
gray_top * (1 - 0.0) + 0.0 * gray_bottom 
frac = 0.25 
gray_top * (1 - 0.25) + 0.25 * gray_bottom 
frac = 0.75 
gray_top * (1 - 0.75) + 0.75 * gray_bottom 
frac = 1.0 
gray_top * (1 - 1) + 1.0 * gray_bottom 
float frac = (float)y / h; // 0.0 … 1.0 
row_gray = gray_top * (1 - frac) + frac * gray_bottom
AVOIDING FLOATS 
float frac = (float)y / h; // 0.0 … 1.0 
row_gray = gray_top * (1 - frac) + frac * gray_bottom 
// 1 * h = h 
// frac * h = y 
uint8_t row_gray = (uint8_t)((gray_top * (h - y) + y * gray_bottom) / h);
DOING LIVE DITHERING 
gray_top 
gray_bottom 
static GColor color_for_gray(int16_t x, int16_t y, uint8_t gray); 
! 
static void update_proc_draw_pixel(Layer *layer, GContext *ctx) { 
! 
! 
! 
} 
const int16_t h = window_size.h; 
for (int16_t y = 0; y < h; y++) { 
! 
! 
! 
! 
} 
uint8_t row_gray = (uint8_t)((gray_top * (h - y) + y * gray_bottom) / h);
DOING LIVE DITHERING 
gray_top 
gray_bottom 
static GColor color_for_gray(int16_t x, int16_t y, uint8_t gray); 
! 
static void update_proc_draw_pixel(Layer *layer, GContext *ctx) { 
const int16_t h = window_size.h; 
for (int16_t y = 0; y < h; y++) { 
uint8_t row_gray = (uint8_t)((gray_top * (h - y) + y * gray_bottom) / h); 
for (int16_t x = 0; x < window_size.w; x++) { 
graphics_context_set_stroke_color(ctx, color_for_gray(x, y, row_gray)); 
graphics_draw_pixel(ctx, GPoint(x, y)); 
} 
! 
! 
! 
! 
! 
! 
} 
! 
}
source: https://www.youtube.com/watch?v=V5O8gj0SQZ0
DOING FAST(!) LIVE DITHERING 
GBitmap 
* graphics_capture_frame_buffer(GContext* ctx) 
Gives you a GBitmap to represent the current frame buffer 
bool graphics_release_frame_buffer(GContext* ctx, GBitmap* buffer) 
…and locks out any other graphic function until you release it
GBITMAP RECAP 
0 
4 
8 
12 
16 
29px 
4 bytes per row 
5px 
unused 
unused 
unused 
unused 
unused 
Fragment of 8 pixels in a row, stored 
in 8 bits or 1 byte (with value 0x5C). 0 1 0 1 1 1 0 0 
Fragment of 8 pixels in a row, stored 
in 8 bits or 1 byte (with value 0x5C). 0 1 0 1 1 1 0 0 
GBitmap 
typedef struct { 
void *addr; 
uint16_t row_size_bytes; 
// ... 
GRect bounds; 
} GBitmap; 
uint8_t *byte_offset = (uint8_t*)bmp->addr 
; 
byte_offset += x / 8; 
byte_offset *= y * bmp->row_size_bytes;
DOING FAST(!) LIVE DITHERING 
static void update_proc_frame_buffer(Layer *layer, GContext *ctx) { 
GBitmap *fb = graphics_capture_frame_buffer(ctx); 
! 
uint8_t *row = (uint8_t *)fb->addr; 
! 
row += fb->bounds.origin.y * fb->row_size_bytes; 
! 
! 
! 
! 
! 
! 
! 
! 
! 
! 
! 
! 
! 
! 
const int16_t h = fb->bounds.size.h; 
for (int16_t y = fb->bounds.origin.y; y < h; y++) { 
uint8_t row_gray_value = (uint8_t)((gray_top * (h - y) + y * gray_bottom) / h); 
! 
! 
! 
! 
uint8_t row_gray_dither_pattern = d i t h e r _ p a t t e r n _ 8 (y, row_gray_value); 
row += fb->row_size_bytes; 
} 
! 
! 
! 
graphics_release_frame_buffer(ctx, fb); 
}
RENDER 8 PIXELS AT ONCE 
static uint8_t (int16_t y, uint8_t gray) { 
return color_for_gray(0, y, gray) << 7 | 
color_for_gray(1, y, gray) << 6 | 
color_for_gray(2, y, gray) << 5 | 
color_for_gray(3, y, gray) << 4 | 
color_for_gray(4, y, gray) << 3 | 
color_for_gray(5, y, gray) << 2 | 
color_for_gray(6, y, gray) << 1 | 
color_for_gray(7, y, gray) << 0; 
} 
dither_pattern_8
DOING FAST(!) LIVE DITHERING 
static void update_proc_frame_buffer(Layer *layer, GContext *ctx) { 
GBitmap *fb = graphics_capture_frame_buffer(ctx); 
! 
uint8_t *row = (uint8_t *)fb->addr; 
! 
row += fb->bounds.origin.y * fb->row_size_bytes; 
! 
! 
! 
! 
! 
! 
! 
! 
! 
! 
! 
! 
! 
! 
const int16_t h = fb->bounds.size.h; 
for (int16_t y = fb->bounds.origin.y; y < h; y++) { 
uint8_t row_gray_value = (uint8_t)((gray_top * (h - y) + y * gray_bottom) / h); 
! 
! 
! 
! 
uint8_t row_gray_dither_pattern = d i t h e r _ p a t t e r n _ 8 (y, row_gray_value); 
memset(row, row_gray_dither_pattern, fb->row_size_bytes); 
row += fb->row_size_bytes; 
} 
! 
! 
! 
graphics_release_frame_buffer(ctx, fb); 
}
source: https://www.youtube.com/watch?v=V5O8gj0SQZ0
BOING 
BALL
Q&A 
source: https://www.youtube.com/watch?v=Z2QMG9UwXI0

More Related Content

What's hot

Data made out of functions
Data made out of functionsData made out of functions
Data made out of functionskenbot
 
COMPUTER GRAPHICS LAB MANUAL
COMPUTER GRAPHICS LAB MANUALCOMPUTER GRAPHICS LAB MANUAL
COMPUTER GRAPHICS LAB MANUALVivek Kumar Sinha
 
All I Needed for Functional Programming I Learned in High School Algebra
All I Needed for Functional Programming I Learned in High School AlgebraAll I Needed for Functional Programming I Learned in High School Algebra
All I Needed for Functional Programming I Learned in High School AlgebraEric Normand
 
Circles graphic
Circles graphicCircles graphic
Circles graphicalldesign
 
FEAL - CSAW CTF 2014 Quals Crypto300
FEAL - CSAW CTF 2014 Quals Crypto300FEAL - CSAW CTF 2014 Quals Crypto300
FEAL - CSAW CTF 2014 Quals Crypto300YOKARO-MON
 
Postfix Evaluations using Stack
Postfix Evaluations using StackPostfix Evaluations using Stack
Postfix Evaluations using StackSoumen Santra
 
Go Containers
Go ContainersGo Containers
Go Containersjgrahamc
 
Csphtp1 07
Csphtp1 07Csphtp1 07
Csphtp1 07HUST
 
imager package in R and examples..
imager package in R and examples..imager package in R and examples..
imager package in R and examples..Dr. Volkan OBAN
 
Register Allocation
Register AllocationRegister Allocation
Register AllocationEelco Visser
 
Isc computer project final upload last
Isc computer project final upload lastIsc computer project final upload last
Isc computer project final upload lastArunav Ray
 
Class list data structure
Class list data structureClass list data structure
Class list data structureKatang Isip
 
Gentle Introduction to Functional Programming
Gentle Introduction to Functional ProgrammingGentle Introduction to Functional Programming
Gentle Introduction to Functional ProgrammingSaurabh Singh
 

What's hot (20)

Computer Science Assignment Help
Computer Science Assignment HelpComputer Science Assignment Help
Computer Science Assignment Help
 
Data made out of functions
Data made out of functionsData made out of functions
Data made out of functions
 
COMPUTER GRAPHICS LAB MANUAL
COMPUTER GRAPHICS LAB MANUALCOMPUTER GRAPHICS LAB MANUAL
COMPUTER GRAPHICS LAB MANUAL
 
All I Needed for Functional Programming I Learned in High School Algebra
All I Needed for Functional Programming I Learned in High School AlgebraAll I Needed for Functional Programming I Learned in High School Algebra
All I Needed for Functional Programming I Learned in High School Algebra
 
Circles graphic
Circles graphicCircles graphic
Circles graphic
 
FEAL - CSAW CTF 2014 Quals Crypto300
FEAL - CSAW CTF 2014 Quals Crypto300FEAL - CSAW CTF 2014 Quals Crypto300
FEAL - CSAW CTF 2014 Quals Crypto300
 
Postfix Evaluations using Stack
Postfix Evaluations using StackPostfix Evaluations using Stack
Postfix Evaluations using Stack
 
Go Containers
Go ContainersGo Containers
Go Containers
 
Python (1)
Python (1)Python (1)
Python (1)
 
Java programs
Java programsJava programs
Java programs
 
Software Construction Assignment Help
Software Construction Assignment HelpSoftware Construction Assignment Help
Software Construction Assignment Help
 
Csphtp1 07
Csphtp1 07Csphtp1 07
Csphtp1 07
 
EGL 1.4 Reference Card
EGL 1.4 Reference CardEGL 1.4 Reference Card
EGL 1.4 Reference Card
 
Lecture 2 f17
Lecture 2 f17Lecture 2 f17
Lecture 2 f17
 
imager package in R and examples..
imager package in R and examples..imager package in R and examples..
imager package in R and examples..
 
Register Allocation
Register AllocationRegister Allocation
Register Allocation
 
Advance java
Advance javaAdvance java
Advance java
 
Isc computer project final upload last
Isc computer project final upload lastIsc computer project final upload last
Isc computer project final upload last
 
Class list data structure
Class list data structureClass list data structure
Class list data structure
 
Gentle Introduction to Functional Programming
Gentle Introduction to Functional ProgrammingGentle Introduction to Functional Programming
Gentle Introduction to Functional Programming
 

Similar to Advanced Techniques: Graphics | Pebble Developer Retreat 2014

lec1_matlab.ppt basic all operations matlab operations
lec1_matlab.ppt basic all operations matlab operationslec1_matlab.ppt basic all operations matlab operations
lec1_matlab.ppt basic all operations matlab operationssamraj sundarraj
 
Image processing spatialfiltering
Image processing spatialfilteringImage processing spatialfiltering
Image processing spatialfilteringJohn Williams
 
C Graphics Functions
C Graphics FunctionsC Graphics Functions
C Graphics FunctionsSHAKOOR AB
 
Computer graphics
Computer graphicsComputer graphics
Computer graphicssnelkoli
 
Creating an Uber Clone - Part IV - Transcript.pdf
Creating an Uber Clone - Part IV - Transcript.pdfCreating an Uber Clone - Part IV - Transcript.pdf
Creating an Uber Clone - Part IV - Transcript.pdfShaiAlmog1
 
2Bytesprog2 course_2014_c9_graph
2Bytesprog2 course_2014_c9_graph2Bytesprog2 course_2014_c9_graph
2Bytesprog2 course_2014_c9_graphkinan keshkeh
 
COMPAPPABCA49085rFunrAP__Practical Number 9 & 10.docx
COMPAPPABCA49085rFunrAP__Practical Number 9 & 10.docxCOMPAPPABCA49085rFunrAP__Practical Number 9 & 10.docx
COMPAPPABCA49085rFunrAP__Practical Number 9 & 10.docxTashiBhutia12
 
XIX PUG-PE - Pygame game development
XIX PUG-PE - Pygame game developmentXIX PUG-PE - Pygame game development
XIX PUG-PE - Pygame game developmentmatheuscmpm
 
Making of-the-logistic-map-bifurcation-diagram
Making of-the-logistic-map-bifurcation-diagramMaking of-the-logistic-map-bifurcation-diagram
Making of-the-logistic-map-bifurcation-diagrammartsberger
 
14multithreaded Graphics
14multithreaded Graphics14multithreaded Graphics
14multithreaded GraphicsAdil Jafri
 
Gems of GameplayKit. UA Mobile 2017.
Gems of GameplayKit. UA Mobile 2017.Gems of GameplayKit. UA Mobile 2017.
Gems of GameplayKit. UA Mobile 2017.UA Mobile
 
Sergey Shelpuk & Olha Romaniuk - “Deep learning, Tensorflow, and Fashion: how...
Sergey Shelpuk & Olha Romaniuk - “Deep learning, Tensorflow, and Fashion: how...Sergey Shelpuk & Olha Romaniuk - “Deep learning, Tensorflow, and Fashion: how...
Sergey Shelpuk & Olha Romaniuk - “Deep learning, Tensorflow, and Fashion: how...Lviv Startup Club
 
Computer Graphics Unit 1
Computer Graphics Unit 1Computer Graphics Unit 1
Computer Graphics Unit 1aravindangc
 

Similar to Advanced Techniques: Graphics | Pebble Developer Retreat 2014 (20)

lec1_matlab.ppt basic all operations matlab operations
lec1_matlab.ppt basic all operations matlab operationslec1_matlab.ppt basic all operations matlab operations
lec1_matlab.ppt basic all operations matlab operations
 
Deep learning
Deep learningDeep learning
Deep learning
 
Image processing spatialfiltering
Image processing spatialfilteringImage processing spatialfiltering
Image processing spatialfiltering
 
Pygame presentation
Pygame presentationPygame presentation
Pygame presentation
 
C Graphics Functions
C Graphics FunctionsC Graphics Functions
C Graphics Functions
 
Computer graphics
Computer graphicsComputer graphics
Computer graphics
 
Creating an Uber Clone - Part IV - Transcript.pdf
Creating an Uber Clone - Part IV - Transcript.pdfCreating an Uber Clone - Part IV - Transcript.pdf
Creating an Uber Clone - Part IV - Transcript.pdf
 
2Bytesprog2 course_2014_c9_graph
2Bytesprog2 course_2014_c9_graph2Bytesprog2 course_2014_c9_graph
2Bytesprog2 course_2014_c9_graph
 
Scmad Chapter06
Scmad Chapter06Scmad Chapter06
Scmad Chapter06
 
COMPAPPABCA49085rFunrAP__Practical Number 9 & 10.docx
COMPAPPABCA49085rFunrAP__Practical Number 9 & 10.docxCOMPAPPABCA49085rFunrAP__Practical Number 9 & 10.docx
COMPAPPABCA49085rFunrAP__Practical Number 9 & 10.docx
 
XIX PUG-PE - Pygame game development
XIX PUG-PE - Pygame game developmentXIX PUG-PE - Pygame game development
XIX PUG-PE - Pygame game development
 
Making of-the-logistic-map-bifurcation-diagram
Making of-the-logistic-map-bifurcation-diagramMaking of-the-logistic-map-bifurcation-diagram
Making of-the-logistic-map-bifurcation-diagram
 
Seeing Like Software
Seeing Like SoftwareSeeing Like Software
Seeing Like Software
 
14multithreaded Graphics
14multithreaded Graphics14multithreaded Graphics
14multithreaded Graphics
 
Introduction to graphics programming in c
Introduction to graphics programming in cIntroduction to graphics programming in c
Introduction to graphics programming in c
 
SCIPY-SYMPY.pdf
SCIPY-SYMPY.pdfSCIPY-SYMPY.pdf
SCIPY-SYMPY.pdf
 
Gems of GameplayKit. UA Mobile 2017.
Gems of GameplayKit. UA Mobile 2017.Gems of GameplayKit. UA Mobile 2017.
Gems of GameplayKit. UA Mobile 2017.
 
Sergey Shelpuk & Olha Romaniuk - “Deep learning, Tensorflow, and Fashion: how...
Sergey Shelpuk & Olha Romaniuk - “Deep learning, Tensorflow, and Fashion: how...Sergey Shelpuk & Olha Romaniuk - “Deep learning, Tensorflow, and Fashion: how...
Sergey Shelpuk & Olha Romaniuk - “Deep learning, Tensorflow, and Fashion: how...
 
Computer Graphics Unit 1
Computer Graphics Unit 1Computer Graphics Unit 1
Computer Graphics Unit 1
 
Extreme dxt compression
Extreme dxt compressionExtreme dxt compression
Extreme dxt compression
 

More from Pebble Technology

#PDR15 - Awesome Appstore Assets
#PDR15 - Awesome Appstore Assets#PDR15 - Awesome Appstore Assets
#PDR15 - Awesome Appstore AssetsPebble Technology
 
#PDR15 - Smartstrap Workshop
#PDR15 - Smartstrap Workshop#PDR15 - Smartstrap Workshop
#PDR15 - Smartstrap WorkshopPebble Technology
 
#PDR15 - Data Analytics and Pebble
#PDR15 - Data Analytics and Pebble#PDR15 - Data Analytics and Pebble
#PDR15 - Data Analytics and PebblePebble Technology
 
#PDR15 - Best Use Cases For Timeline
#PDR15 - Best Use Cases For Timeline#PDR15 - Best Use Cases For Timeline
#PDR15 - Best Use Cases For TimelinePebble Technology
 
#PDR15 - waf, wscript and Your Pebble App
#PDR15 - waf, wscript and Your Pebble App#PDR15 - waf, wscript and Your Pebble App
#PDR15 - waf, wscript and Your Pebble AppPebble Technology
 
#PDR15 Creating Pebble Apps for Aplite, Basalt, and Chalk
#PDR15 Creating Pebble Apps for Aplite, Basalt, and Chalk#PDR15 Creating Pebble Apps for Aplite, Basalt, and Chalk
#PDR15 Creating Pebble Apps for Aplite, Basalt, and ChalkPebble Technology
 
#PDR15 - Designing for Pebble
#PDR15 - Designing for Pebble#PDR15 - Designing for Pebble
#PDR15 - Designing for PebblePebble Technology
 
Overlay & Libraries | Pebble Meetup Oct. 2014
Overlay & Libraries | Pebble Meetup Oct. 2014Overlay & Libraries | Pebble Meetup Oct. 2014
Overlay & Libraries | Pebble Meetup Oct. 2014Pebble Technology
 
Connecting Pebble to the World
Connecting Pebble to the WorldConnecting Pebble to the World
Connecting Pebble to the WorldPebble Technology
 
Guest Presentation - Strap | Pebble Developer Retreat 2014
Guest Presentation - Strap | Pebble Developer Retreat 2014Guest Presentation - Strap | Pebble Developer Retreat 2014
Guest Presentation - Strap | Pebble Developer Retreat 2014Pebble Technology
 
Battery Life | Pebble Developer Retreat 2014
Battery Life | Pebble Developer Retreat 2014Battery Life | Pebble Developer Retreat 2014
Battery Life | Pebble Developer Retreat 2014Pebble Technology
 
Thomas Sarlandie Kickoff Talk | Pebble Developer Retreat 2014
Thomas Sarlandie Kickoff Talk | Pebble Developer Retreat 2014Thomas Sarlandie Kickoff Talk | Pebble Developer Retreat 2014
Thomas Sarlandie Kickoff Talk | Pebble Developer Retreat 2014Pebble Technology
 
Advanced Techniques: Size | Pebble Developer Retreat 2014
Advanced Techniques: Size | Pebble Developer Retreat 2014Advanced Techniques: Size | Pebble Developer Retreat 2014
Advanced Techniques: Size | Pebble Developer Retreat 2014Pebble Technology
 

More from Pebble Technology (20)

#PDR15 - Awesome Appstore Assets
#PDR15 - Awesome Appstore Assets#PDR15 - Awesome Appstore Assets
#PDR15 - Awesome Appstore Assets
 
#PDR15 - Smartstrap Workshop
#PDR15 - Smartstrap Workshop#PDR15 - Smartstrap Workshop
#PDR15 - Smartstrap Workshop
 
#PDR15 - Data Analytics and Pebble
#PDR15 - Data Analytics and Pebble#PDR15 - Data Analytics and Pebble
#PDR15 - Data Analytics and Pebble
 
#PDR15 - Best Use Cases For Timeline
#PDR15 - Best Use Cases For Timeline#PDR15 - Best Use Cases For Timeline
#PDR15 - Best Use Cases For Timeline
 
#PDR15 - waf, wscript and Your Pebble App
#PDR15 - waf, wscript and Your Pebble App#PDR15 - waf, wscript and Your Pebble App
#PDR15 - waf, wscript and Your Pebble App
 
#PDR15 - PebbleKit iOS 3.0
#PDR15 - PebbleKit iOS 3.0#PDR15 - PebbleKit iOS 3.0
#PDR15 - PebbleKit iOS 3.0
 
#PDR15 - Voice API
#PDR15 - Voice API#PDR15 - Voice API
#PDR15 - Voice API
 
#PDR15 - Pebble Graphics
#PDR15 - Pebble Graphics#PDR15 - Pebble Graphics
#PDR15 - Pebble Graphics
 
#PDR15 Creating Pebble Apps for Aplite, Basalt, and Chalk
#PDR15 Creating Pebble Apps for Aplite, Basalt, and Chalk#PDR15 Creating Pebble Apps for Aplite, Basalt, and Chalk
#PDR15 Creating Pebble Apps for Aplite, Basalt, and Chalk
 
#PDR15 - Designing for Pebble
#PDR15 - Designing for Pebble#PDR15 - Designing for Pebble
#PDR15 - Designing for Pebble
 
#PDR15 Kick-Off
#PDR15 Kick-Off#PDR15 Kick-Off
#PDR15 Kick-Off
 
Pebble Slate Workshop
Pebble Slate WorkshopPebble Slate Workshop
Pebble Slate Workshop
 
Overlay & Libraries | Pebble Meetup Oct. 2014
Overlay & Libraries | Pebble Meetup Oct. 2014Overlay & Libraries | Pebble Meetup Oct. 2014
Overlay & Libraries | Pebble Meetup Oct. 2014
 
Connecting Pebble to the World
Connecting Pebble to the WorldConnecting Pebble to the World
Connecting Pebble to the World
 
Guest Presentation - Strap | Pebble Developer Retreat 2014
Guest Presentation - Strap | Pebble Developer Retreat 2014Guest Presentation - Strap | Pebble Developer Retreat 2014
Guest Presentation - Strap | Pebble Developer Retreat 2014
 
Battery Life | Pebble Developer Retreat 2014
Battery Life | Pebble Developer Retreat 2014Battery Life | Pebble Developer Retreat 2014
Battery Life | Pebble Developer Retreat 2014
 
Thomas Sarlandie Kickoff Talk | Pebble Developer Retreat 2014
Thomas Sarlandie Kickoff Talk | Pebble Developer Retreat 2014Thomas Sarlandie Kickoff Talk | Pebble Developer Retreat 2014
Thomas Sarlandie Kickoff Talk | Pebble Developer Retreat 2014
 
Advanced Techniques: Size | Pebble Developer Retreat 2014
Advanced Techniques: Size | Pebble Developer Retreat 2014Advanced Techniques: Size | Pebble Developer Retreat 2014
Advanced Techniques: Size | Pebble Developer Retreat 2014
 
Pebble wearables devcon
Pebble wearables devconPebble wearables devcon
Pebble wearables devcon
 
Announcing Pebble SDK 2.0
Announcing Pebble SDK 2.0Announcing Pebble SDK 2.0
Announcing Pebble SDK 2.0
 

Recently uploaded

Portal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russePortal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russe中 央社
 
The Ultimate Prompt Engineering Guide for Generative AI: Get the Most Out of ...
The Ultimate Prompt Engineering Guide for Generative AI: Get the Most Out of ...The Ultimate Prompt Engineering Guide for Generative AI: Get the Most Out of ...
The Ultimate Prompt Engineering Guide for Generative AI: Get the Most Out of ...SOFTTECHHUB
 
How to Check GPS Location with a Live Tracker in Pakistan
How to Check GPS Location with a Live Tracker in PakistanHow to Check GPS Location with a Live Tracker in Pakistan
How to Check GPS Location with a Live Tracker in Pakistandanishmna97
 
ChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps ProductivityChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps ProductivityVictorSzoltysek
 
How we scaled to 80K users by doing nothing!.pdf
How we scaled to 80K users by doing nothing!.pdfHow we scaled to 80K users by doing nothing!.pdf
How we scaled to 80K users by doing nothing!.pdfSrushith Repakula
 
Top 10 CodeIgniter Development Companies
Top 10 CodeIgniter Development CompaniesTop 10 CodeIgniter Development Companies
Top 10 CodeIgniter Development CompaniesTopCSSGallery
 
UiPath manufacturing technology benefits and AI overview
UiPath manufacturing technology benefits and AI overviewUiPath manufacturing technology benefits and AI overview
UiPath manufacturing technology benefits and AI overviewDianaGray10
 
How to Check CNIC Information Online with Pakdata cf
How to Check CNIC Information Online with Pakdata cfHow to Check CNIC Information Online with Pakdata cf
How to Check CNIC Information Online with Pakdata cfdanishmna97
 
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider  Progress from Awareness to Implementation.pptxTales from a Passkey Provider  Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider Progress from Awareness to Implementation.pptxFIDO Alliance
 
Generative AI Use Cases and Applications.pdf
Generative AI Use Cases and Applications.pdfGenerative AI Use Cases and Applications.pdf
Generative AI Use Cases and Applications.pdfalexjohnson7307
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxFIDO Alliance
 
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...FIDO Alliance
 
Intro to Passkeys and the State of Passwordless.pptx
Intro to Passkeys and the State of Passwordless.pptxIntro to Passkeys and the State of Passwordless.pptx
Intro to Passkeys and the State of Passwordless.pptxFIDO Alliance
 
JohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard37
 
JavaScript Usage Statistics 2024 - The Ultimate Guide
JavaScript Usage Statistics 2024 - The Ultimate GuideJavaScript Usage Statistics 2024 - The Ultimate Guide
JavaScript Usage Statistics 2024 - The Ultimate GuidePixlogix Infotech
 
(Explainable) Data-Centric AI: what are you explaininhg, and to whom?
(Explainable) Data-Centric AI: what are you explaininhg, and to whom?(Explainable) Data-Centric AI: what are you explaininhg, and to whom?
(Explainable) Data-Centric AI: what are you explaininhg, and to whom?Paolo Missier
 
ERP Contender Series: Acumatica vs. Sage Intacct
ERP Contender Series: Acumatica vs. Sage IntacctERP Contender Series: Acumatica vs. Sage Intacct
ERP Contender Series: Acumatica vs. Sage IntacctBrainSell Technologies
 
Continuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on ThanabotsContinuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on ThanabotsLeah Henrickson
 
Event-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream ProcessingEvent-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream ProcessingScyllaDB
 
Introduction to FIDO Authentication and Passkeys.pptx
Introduction to FIDO Authentication and Passkeys.pptxIntroduction to FIDO Authentication and Passkeys.pptx
Introduction to FIDO Authentication and Passkeys.pptxFIDO Alliance
 

Recently uploaded (20)

Portal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russePortal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russe
 
The Ultimate Prompt Engineering Guide for Generative AI: Get the Most Out of ...
The Ultimate Prompt Engineering Guide for Generative AI: Get the Most Out of ...The Ultimate Prompt Engineering Guide for Generative AI: Get the Most Out of ...
The Ultimate Prompt Engineering Guide for Generative AI: Get the Most Out of ...
 
How to Check GPS Location with a Live Tracker in Pakistan
How to Check GPS Location with a Live Tracker in PakistanHow to Check GPS Location with a Live Tracker in Pakistan
How to Check GPS Location with a Live Tracker in Pakistan
 
ChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps ProductivityChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps Productivity
 
How we scaled to 80K users by doing nothing!.pdf
How we scaled to 80K users by doing nothing!.pdfHow we scaled to 80K users by doing nothing!.pdf
How we scaled to 80K users by doing nothing!.pdf
 
Top 10 CodeIgniter Development Companies
Top 10 CodeIgniter Development CompaniesTop 10 CodeIgniter Development Companies
Top 10 CodeIgniter Development Companies
 
UiPath manufacturing technology benefits and AI overview
UiPath manufacturing technology benefits and AI overviewUiPath manufacturing technology benefits and AI overview
UiPath manufacturing technology benefits and AI overview
 
How to Check CNIC Information Online with Pakdata cf
How to Check CNIC Information Online with Pakdata cfHow to Check CNIC Information Online with Pakdata cf
How to Check CNIC Information Online with Pakdata cf
 
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider  Progress from Awareness to Implementation.pptxTales from a Passkey Provider  Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
 
Generative AI Use Cases and Applications.pdf
Generative AI Use Cases and Applications.pdfGenerative AI Use Cases and Applications.pdf
Generative AI Use Cases and Applications.pdf
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
 
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
 
Intro to Passkeys and the State of Passwordless.pptx
Intro to Passkeys and the State of Passwordless.pptxIntro to Passkeys and the State of Passwordless.pptx
Intro to Passkeys and the State of Passwordless.pptx
 
JohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptx
 
JavaScript Usage Statistics 2024 - The Ultimate Guide
JavaScript Usage Statistics 2024 - The Ultimate GuideJavaScript Usage Statistics 2024 - The Ultimate Guide
JavaScript Usage Statistics 2024 - The Ultimate Guide
 
(Explainable) Data-Centric AI: what are you explaininhg, and to whom?
(Explainable) Data-Centric AI: what are you explaininhg, and to whom?(Explainable) Data-Centric AI: what are you explaininhg, and to whom?
(Explainable) Data-Centric AI: what are you explaininhg, and to whom?
 
ERP Contender Series: Acumatica vs. Sage Intacct
ERP Contender Series: Acumatica vs. Sage IntacctERP Contender Series: Acumatica vs. Sage Intacct
ERP Contender Series: Acumatica vs. Sage Intacct
 
Continuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on ThanabotsContinuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
 
Event-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream ProcessingEvent-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream Processing
 
Introduction to FIDO Authentication and Passkeys.pptx
Introduction to FIDO Authentication and Passkeys.pptxIntroduction to FIDO Authentication and Passkeys.pptx
Introduction to FIDO Authentication and Passkeys.pptx
 

Advanced Techniques: Graphics | Pebble Developer Retreat 2014

  • 1. GRAPHICS MATT & HEIKO – DEVELOPER EXPERIENCE ENGINEERS ON TWITTER AS @MTHUNGERFORD & @HBEHRENS
  • 2. THE DISPLAY 144x168px @ 175 DPI black & white only 25+ FPS
  • 3. CONTENT A Pixel’s Journey Dithering Accessing the Frame Buffer
  • 5. LAYER STACK Layers are added to the layer_stack from back to front starting from the window layer. ! Layers are then rendered from back to front into the application frame buffer. Window
  • 6. THE COMPOSITOR Example of a non-fullscreen application (144x152): Application frame buffer Compositor frame buffer Final display
  • 7. GRAPHICS APIS static void custom_update_proc(Layer *layer, GContext *ctx); Layer-equivalents working directly on GContext graphics_draw_text, graphics_draw_bitmap_in_rect Drawings vector graphics gpath_draw_filled, gpath_draw_outline Drawings raster graphics graphics_draw_pixel, graphics_draw_line graphics_draw_circle, graphics_fill_circle, graphics_draw_rect, graphics_draw_round_rect, graphics_fill_rect Animate graphics app_timer_register, app_timer_reschedule, app_timer_cancel Animation, PropertyAnimation
  • 9. GRAPHICS APIS static void custom_update_proc(Layer *layer, GContext *ctx); Layer-equivalents working directly on GContext graphics_draw_text, graphics_draw_bitmap_in_rect Drawings vector graphics gpath_draw_filled, gpath_draw_outline Drawings raster graphics graphics_draw_pixel, graphics_draw_line graphics_draw_circle, graphics_fill_circle, graphics_draw_rect, graphics_draw_round_rect, graphics_fill_rect Animate graphics app_timer_register, app_timer_reschedule, app_timer_cancel Animation, PropertyAnimation
  • 10. Drawings advanced raster graphics graphics_capture_frame_buffer, graphics_release_frame_buffer Doing dithering at runtime
  • 12.
  • 13.
  • 14. Dither is an intentionally applied form of noise used to randomize quantization error, preventing large-scale patterns such as color banding in images. http://en.wikipedia.org/wiki/Dither 256 shades of gray 16 shades of gray + nearest color 16 shades of gray + random noise 16 shades of gray + ordered dithering
  • 15. 256 shades of gray 16 SHADES OF GRAY 16 shades of gray + nearest color 16 shades of gray + random noise 16 shades of gray + ordered dithering BLACK AND WHITE black & white + nearest color black & white + noise black & white + ordered dithering
  • 16. original ordered dithering Floyd-Steinberg dithering nearest color
  • 17. FLOYD-STEINBERG DITHERING for each y from top to bottom for each x from left to right oldpixel := pixel[x][y] newpixel := find_closest_palette_color(oldpixel) pixel[x][y] := newpixel quant_error := oldpixel - newpixel pixel[x+1][y ] := pixel[x+1][y ] + quant_error * 7/16 pixel[x-1][y+1] := pixel[x-1][y+1] + quant_error * 3/16 pixel[x ][y+1] := pixel[x ][y+1] + quant_error * 5/16 pixel[x+1][y+1] := pixel[x+1][y+1] + quant_error * 1/16 ORDERED DITHERING (BAYER MATRIX) threshold_map_4x4 = foreach y foreach x oldpixel := pixel[x][y] + threshold_map_4x4[x mod 4][y mod 4] newpixel := find_closest_palette_color(oldpixel) pixel[x][y] := newpixel
  • 18. source: Joel Yliluoma’s dithering page - http://bisqwit.iki.fi/story/howto/dither/jy/ original from PSX game “Chrono Cross”
  • 19. source: Joel Yliluoma’s dithering page - http://bisqwit.iki.fi/story/howto/dither/jy/ nearest neighbor to 12 colors
  • 20. source: Joel Yliluoma’s dithering page - http://bisqwit.iki.fi/story/howto/dither/jy/ Floyd-Steinberg to 12 colors
  • 22. BETTER BITMAPS (GIMP/PHOTOSHOP) Resize to desired size (<144x168) using sinc filter Convert image to grayscale Modify brightness/contrast to sharpen image Posterize to 3 colors (if dithering to gray_50) or 2 colors for black and white. Undo-Redo brightness/contrast & posterize till desired effect Convert image to black and white with ordered (positional) dithering
  • 23. Better Bitmaps (GIMP/Photoshop) Open Original Image in the GIMP/Photoshop
  • 24. Better Bitmaps (GIMP/Photoshop) Resize: Image -> Scale Image
  • 25. Better Bitmaps (GIMP/Photoshop) Resize to desired size (<144x168) using sinc filter
  • 26. Better Bitmaps (GIMP/Photoshop) Grayscale: Image -> Mode -> Grayscale
  • 27. Better Bitmaps (GIMP/Photoshop) Brightness-Contrast: Colors -> Brightness-Contrast
  • 28. Better Bitmaps (GIMP/Photoshop) Slide contrast to right to remove colors and balance with brightness
  • 29. Better Bitmaps (GIMP/Photoshop) Posterize: Colors -> Posterize
  • 30. Better Bitmaps (GIMP/Photoshop) Posterize: Select 3 colors (2 for black & white only). 3rd color is Gray.
  • 31. Better Bitmaps (GIMP/Photoshop) Convert to 1-bit (b&w): Image -> Mode -> Indexed
  • 32. Better Bitmaps (GIMP/Photoshop) Select b&w, choose dithering Positioned (Ordered) for dithered gray
  • 33. Better Bitmaps (GIMP/Photoshop) Final Product: Robot with dithered gray_50
  • 34. BETTER BITMAPS (IMAGEMAGICK) convert orig.png -adaptive-resize '144x168>' -fill '#FFFFFF00' -opaque none -type Grayscale -colorspace Gray -black-threshold 30% -white-threshold 70% -ordered-dither 2x1 -colors 2 -depth 1 -define png:compression-level=9 -define png:compression-strategy=0 -define png:exclude-chunk=all new.png
  • 35. DITHERED ANIMATIONS (APNG) ImageMagick scripting ! Ordered dithering (gray_50) ! (a)PNG compression for 200 frames ! Resource loading and drawing at high FPS (10 FPS in this example)
  • 36.
  • 39. PRE-DITHERED FLOYD STEINBERG ORDERED DITHERING
  • 46. PRE-DITHERED FLOYD STEINBERG ORDERED DITHERING
  • 47. source: Joel Yliluoma’s dithering page - http://bisqwit.iki.fi/story/howto/dither/jy/ reduction to 18 colors
  • 49. ORDERED DITHERING (BAYER MATRIX) threshold_map_4x4 = foreach y foreach x oldpixel := pixel[x][y] + threshold_map_4x4[x mod 4][y mod 4] newpixel := find_closest_palette_color(oldpixel) pixel[x][y] := newpixel ORDERED DITHERING BLACK & WHITE foreach y foreach x newpixel := pixel[x][y] > threshold_map_8x8[x mod 8][y mod 8] ? white : black; pixel[x][y] := newpixel
  • 50. ORDERED DITHERING BLACK & WHITE foreach y foreach x newpixel := pixel[x][y] > threshold_map_8x8[x mod 8][y mod 8] ? white : black; pixel[x][y] := newpixel IMPLEMENTED IN C // Bayer matrix for ordered dithering static const uint8_t ditherMatrix[8][8] = { { 0*4, 32*4, 8*4, 40*4, 2*4, 34*4, 10*4, 42*4}, {48*4, 16*4, 56*4, 24*4, 50*4, 18*4, 58*4, 26*4}, {12*4, 44*4, 4*4, 36*4, 14*4, 46*4, 6*4, 38*4}, {60*4, 28*4, 52*4, 20*4, 62*4, 30*4, 54*4, 22*4}, { 3*4, 35*4, 11*4, 43*4, 1*4, 33*4, 9*4, 41*4}, {51*4, 19*4, 59*4, 27*4, 49*4, 17*4, 57*4, 25*4}, {15*4, 47*4, 7*4, 39*4, 13*4, 45*4, 5*4, 37*4}, {63*4, 31*4, 55*4, 23*4, 61*4, 29*4, 53*4, 21*4} }; ! static GColor color_for_gray(int16_t x, int16_t y, uint8_t gray) { return gray > ditherMatrix[y % 8][x % 8] ? GColorWhite : GColorBlack; }
  • 51. DOING LIVE DITHERING gray_top gray_bottom static GColor color_for_gray(int16_t x, int16_t y, uint8_t gray); ! static void update_proc_draw_pixel(Layer *layer, GContext *ctx) { ! ! ! } const int16_t h = window_size.h; for (int16_t y = 0; y < h; y++) { ! ! ! ! } uint8_t row_gray = (uint8_t)((gray_top * (h - y) + y * gray_bottom) / h);
  • 52. AVOIDING FLOATS frac = 0.0 gray_top * (1 - 0.0) + 0.0 * gray_bottom frac = 0.25 gray_top * (1 - 0.25) + 0.25 * gray_bottom frac = 0.75 gray_top * (1 - 0.75) + 0.75 * gray_bottom frac = 1.0 gray_top * (1 - 1) + 1.0 * gray_bottom float frac = (float)y / h; // 0.0 … 1.0 row_gray = gray_top * (1 - frac) + frac * gray_bottom
  • 53. AVOIDING FLOATS float frac = (float)y / h; // 0.0 … 1.0 row_gray = gray_top * (1 - frac) + frac * gray_bottom // 1 * h = h // frac * h = y uint8_t row_gray = (uint8_t)((gray_top * (h - y) + y * gray_bottom) / h);
  • 54. DOING LIVE DITHERING gray_top gray_bottom static GColor color_for_gray(int16_t x, int16_t y, uint8_t gray); ! static void update_proc_draw_pixel(Layer *layer, GContext *ctx) { ! ! ! } const int16_t h = window_size.h; for (int16_t y = 0; y < h; y++) { ! ! ! ! } uint8_t row_gray = (uint8_t)((gray_top * (h - y) + y * gray_bottom) / h);
  • 55. DOING LIVE DITHERING gray_top gray_bottom static GColor color_for_gray(int16_t x, int16_t y, uint8_t gray); ! static void update_proc_draw_pixel(Layer *layer, GContext *ctx) { const int16_t h = window_size.h; for (int16_t y = 0; y < h; y++) { uint8_t row_gray = (uint8_t)((gray_top * (h - y) + y * gray_bottom) / h); for (int16_t x = 0; x < window_size.w; x++) { graphics_context_set_stroke_color(ctx, color_for_gray(x, y, row_gray)); graphics_draw_pixel(ctx, GPoint(x, y)); } ! ! ! ! ! ! } ! }
  • 57. DOING FAST(!) LIVE DITHERING GBitmap * graphics_capture_frame_buffer(GContext* ctx) Gives you a GBitmap to represent the current frame buffer bool graphics_release_frame_buffer(GContext* ctx, GBitmap* buffer) …and locks out any other graphic function until you release it
  • 58. GBITMAP RECAP 0 4 8 12 16 29px 4 bytes per row 5px unused unused unused unused unused Fragment of 8 pixels in a row, stored in 8 bits or 1 byte (with value 0x5C). 0 1 0 1 1 1 0 0 Fragment of 8 pixels in a row, stored in 8 bits or 1 byte (with value 0x5C). 0 1 0 1 1 1 0 0 GBitmap typedef struct { void *addr; uint16_t row_size_bytes; // ... GRect bounds; } GBitmap; uint8_t *byte_offset = (uint8_t*)bmp->addr ; byte_offset += x / 8; byte_offset *= y * bmp->row_size_bytes;
  • 59. DOING FAST(!) LIVE DITHERING static void update_proc_frame_buffer(Layer *layer, GContext *ctx) { GBitmap *fb = graphics_capture_frame_buffer(ctx); ! uint8_t *row = (uint8_t *)fb->addr; ! row += fb->bounds.origin.y * fb->row_size_bytes; ! ! ! ! ! ! ! ! ! ! ! ! ! ! const int16_t h = fb->bounds.size.h; for (int16_t y = fb->bounds.origin.y; y < h; y++) { uint8_t row_gray_value = (uint8_t)((gray_top * (h - y) + y * gray_bottom) / h); ! ! ! ! uint8_t row_gray_dither_pattern = d i t h e r _ p a t t e r n _ 8 (y, row_gray_value); row += fb->row_size_bytes; } ! ! ! graphics_release_frame_buffer(ctx, fb); }
  • 60. RENDER 8 PIXELS AT ONCE static uint8_t (int16_t y, uint8_t gray) { return color_for_gray(0, y, gray) << 7 | color_for_gray(1, y, gray) << 6 | color_for_gray(2, y, gray) << 5 | color_for_gray(3, y, gray) << 4 | color_for_gray(4, y, gray) << 3 | color_for_gray(5, y, gray) << 2 | color_for_gray(6, y, gray) << 1 | color_for_gray(7, y, gray) << 0; } dither_pattern_8
  • 61. DOING FAST(!) LIVE DITHERING static void update_proc_frame_buffer(Layer *layer, GContext *ctx) { GBitmap *fb = graphics_capture_frame_buffer(ctx); ! uint8_t *row = (uint8_t *)fb->addr; ! row += fb->bounds.origin.y * fb->row_size_bytes; ! ! ! ! ! ! ! ! ! ! ! ! ! ! const int16_t h = fb->bounds.size.h; for (int16_t y = fb->bounds.origin.y; y < h; y++) { uint8_t row_gray_value = (uint8_t)((gray_top * (h - y) + y * gray_bottom) / h); ! ! ! ! uint8_t row_gray_dither_pattern = d i t h e r _ p a t t e r n _ 8 (y, row_gray_value); memset(row, row_gray_dither_pattern, fb->row_size_bytes); row += fb->row_size_bytes; } ! ! ! graphics_release_frame_buffer(ctx, fb); }