11 Commits
11 changed files with 91 additions and 258 deletions

No files matched your search

+4 -2
View File
@@ -1,3 +1,5 @@
/.clangd
/build /build
/.lock* /.clangd
/.lock-waf*
/package-lock.json
/node_modules
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2026 hilariouspig Copyright (c) 2026 RandyTheSilly
THIS LICENSE DOES NOT APPLY TO ANY ".png" NOR ".ttf" FILES IN THIS REPOSITORY. THIS LICENSE DOES NOT APPLY TO ANY ".png" NOR ".ttf" FILES IN THIS REPOSITORY.
-7
View File
@@ -20,10 +20,3 @@ Since the original watchface is **NOT** open source, this "port" could be more a
- Add more Maan art (see [this gallery](https://www.flickr.com/photos/53297919@N04/albums/72157624708812279) for potential candidates) - Add more Maan art (see [this gallery](https://www.flickr.com/photos/53297919@N04/albums/72157624708812279) for potential candidates)
- Potential light mode (don't hold your breath - I'm still not sure this would look good and I don't like the idea of having settings) - Potential light mode (don't hold your breath - I'm still not sure this would look good and I don't like the idea of having settings)
- Black&white support if I get bored or Pebble releases a modern b&w watch (Flint doesn't count) - Black&white support if I get bored or Pebble releases a modern b&w watch (Flint doesn't count)
# Development
1. Install the [Pebble SDK](https://developer.repebble.com/sdk/)
2. Clone this repo
3. `pebble build` (some headers needed to satisfy your IDE are generated on first build)
4. If using `clangd`, run `./tools/clangd.zsh` to generate a `.clangd` file to fix various error notifications
5. Hack away and test with `pebble build && pebble install --emulator emery`
-46
View File
@@ -1,46 +0,0 @@
/*
* Example jshint configuration file for Pebble development.
*
* Check out the full documentation at http://www.jshint.com/docs/options/
*/
{
// Declares the existence of the globals available in PebbleKit JS.
"globals": {"console": true, "setTimeout": true, "setInterval": true, "Int8Array": true, "Uint8Array": true, "Uint8ClampedArray": true, "Int16Array": true, "Uint16Array": true, "Int32Array": true, "Uint32Array": true, "Float32Array": true, "Float64Array": true, "Pebble": true, "WebSocket": true, "XMLHttpRequest": true, "navigator": true, "localStorage": true, "require": true, "exports": true, "module": true},
// Do not mess with standard JavaScript objects (Array, Date, etc)
"freeze": true,
// Do not use eval! Keep this warning turned on (ie: false)
"evil": false,
/*
* The options below are more style/developer dependent.
* Customize to your liking.
*/
// All variables should be in camelcase - too specific for CloudPebble builds to fail
// "camelcase": true,
// Do not allow blocks without { } - too specific for CloudPebble builds to fail.
// "curly": true,
// Prohibits the use of immediate function invocations without wrapping them in parentheses
"immed": true,
// Don't enforce indentation, because it's not worth failing builds over
// (especially given our somewhat lacklustre support for it)
"indent": false,
// Do not use a variable before it's defined
"latedef": "nofunc",
// Spot undefined variables
"undef": "true",
// Spot unused variables
"unused": "true",
// Enable ES6 syntax (const, let, arrow functions, etc)
"esversion": 6
}
+6 -2
View File
@@ -1,7 +1,11 @@
{ {
"author": "RandyTheSilly", "author": "RandyTheSilly",
"dependencies": {}, "dependencies": {},
"keywords": [], "keywords": [
"silly",
"creature",
"swap"
],
"name": "maan-on-my-wrist-xl", "name": "maan-on-my-wrist-xl",
"pebble": { "pebble": {
"displayName": "Maan On My Wrist XL", "displayName": "Maan On My Wrist XL",
@@ -752,5 +756,5 @@
"watchface": true "watchface": true
} }
}, },
"version": "1.1.0" "version": "1.1.1"
} }
+77 -129
View File
@@ -1,9 +1,6 @@
#include "palette_manip.h" #include "palette_manip.h"
#include <pebble.h> #include <pebble.h>
// DEBUG memory usage layer
// static TextLayer *s_memory_layer;
// declare general statics // declare general statics
static Window *s_main_window; static Window *s_main_window;
static GFont s_custom_font; static GFont s_custom_font;
@@ -70,7 +67,6 @@ static GRect s_bt_grect_b;
// declare animation templates // declare animation templates
static const uint8_t s_animation_duration = 255; static const uint8_t s_animation_duration = 255;
static bool s_first_tick_occurred = false;
static Animation *s_head_raise_template; static Animation *s_head_raise_template;
static Animation *s_head_out_template; static Animation *s_head_out_template;
static Animation *s_head_in_template; static Animation *s_head_in_template;
@@ -78,6 +74,9 @@ static Animation *s_butt_raise_template;
static Animation *s_butt_out_template; static Animation *s_butt_out_template;
static Animation *s_butt_in_template; static Animation *s_butt_in_template;
// guards for the swap scheduling
static struct tm s_last_swap_time;
// declare lookup tables // declare lookup tables
#if PBL_DISPLAY_WIDTH <= 180 #if PBL_DISPLAY_WIDTH <= 180
static const uint8_t s_ones_offset[] = {0, 3, 6, 9, 12}; static const uint8_t s_ones_offset[] = {0, 3, 6, 9, 12};
@@ -129,25 +128,71 @@ static void destroy_animation_handler(Animation *animation, bool finished, void
animation_destroy(animation); animation_destroy(animation);
} }
static void update_minute_1() { static void schedule_guy_animation(Animation *raise_tmpl, Animation *out_tmpl, Animation *in_tmpl, AnimationStoppedHandler out_handler) {
// get a tm structure Animation *raise = animation_clone(raise_tmpl);
time_t temp = time(NULL); Animation *out = animation_clone(out_tmpl);
struct tm *tick_time = localtime(&temp); animation_set_handlers(out, (AnimationHandlers){.stopped = out_handler}, NULL);
Animation *in = animation_clone(in_tmpl);
Animation *rest = animation_clone(raise_tmpl);
animation_set_reverse(rest, true);
Animation *seq = animation_sequence_create(raise, out, in, rest, NULL);
// set the handler to destroy the sequence (and its children) when finished
animation_set_handlers(seq, (AnimationHandlers){.stopped = destroy_animation_handler}, NULL);
// run it
animation_schedule(seq);
}
// write the current hours and minutes into a buffer & format static void update_minute_30_out_handler(Animation *animation, bool finished, void *context) {
// destroy and reassign
gbitmap_destroy(s_butt);
s_butt_index = rand() % s_butt_count;
s_butt = gbitmap_create_with_resource(s_random_butts[s_butt_index]);
// swap colors
replace_gbitmap_color(GColorGreen, s_random_color_next, s_butt);
replace_gbitmap_color(s_random_color_current, s_random_color_next, s_head);
s_random_color_current = s_random_color_next;
s_random_color_next = s_dark_bg_colors[rand() % s_color_count];
// force update bitmap layers
bitmap_layer_set_bitmap(s_guy_butt_layer, s_butt);
bitmap_layer_set_bitmap(s_guy_head_layer, s_head);
}
static void update_minute_60_out_handler(Animation *animation, bool finished, void *context) {
// destroy and reassign
gbitmap_destroy(s_head);
s_head_index = rand() % s_head_count;
s_head = gbitmap_create_with_resource(s_random_heads[s_head_index]);
// swap colors
replace_gbitmap_color(GColorGreen, s_random_color_next, s_head);
replace_gbitmap_color(s_random_color_current, s_random_color_next, s_butt);
s_random_color_current = s_random_color_next;
s_random_color_next = s_dark_bg_colors[rand() % s_color_count];
// force update bitmap layers
bitmap_layer_set_bitmap(s_guy_head_layer, s_head);
bitmap_layer_set_bitmap(s_guy_butt_layer, s_butt);
}
static bool is_same_minute(const struct tm *a, const struct tm *b) {
return a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour && a->tm_min == b->tm_min;
}
static void minute_handler(struct tm *tick_time, TimeUnits units_changed) {
// time update
static char s_time_buffer[8]; static char s_time_buffer[8];
strftime(s_time_buffer, sizeof(s_time_buffer), clock_is_24h_style() ? "%H:%M" : "%I:%M", tick_time); strftime(s_time_buffer, sizeof(s_time_buffer), clock_is_24h_style() ? "%H:%M" : "%I:%M", tick_time);
text_layer_set_text(s_time_layer, s_time_buffer);
// write the current date into a buffer & format // date update
static char s_date_buffer[16]; static char s_date_buffer[16];
#if PBL_DISPLAY_WIDTH <= 144 #if PBL_DISPLAY_WIDTH <= 144
strftime(s_date_buffer, sizeof(s_date_buffer), "%m%d", tick_time); strftime(s_date_buffer, sizeof(s_date_buffer), "%m%d", tick_time);
#else #else
strftime(s_date_buffer, sizeof(s_date_buffer), "%m.%d", tick_time); strftime(s_date_buffer, sizeof(s_date_buffer), "%m.%d", tick_time);
#endif #endif
// update layers
text_layer_set_text(s_time_layer, s_time_buffer);
text_layer_set_text(s_date_layer, s_date_buffer); text_layer_set_text(s_date_layer, s_date_buffer);
// create date/bt centering animations // create date/bt centering animations
@@ -162,7 +207,7 @@ static void update_minute_1() {
//// calculate new positions //// calculate new positions
s_date_grect_b = GRect(s_ones_offset[ones], s_date_pos_y, s_date_bt_width, s_date_height); s_date_grect_b = GRect(s_ones_offset[ones], s_date_pos_y, s_date_bt_width, s_date_height);
s_bt_grect_b = GRect(s_bt_pos_x - s_ones_offset[ones], s_bt_pos_y, s_date_bt_width, s_bt_height); s_bt_grect_b = GRect(s_bt_pos_x - s_ones_offset[ones], s_bt_pos_y, s_date_bt_width, s_bt_height);
if (s_first_tick_occurred) { // no need to animate before first tick, as positions are set in init() without animating if (units_changed) {
//// configure animations //// configure animations
////// date ////// date
PropertyAnimation *date_center_prop = property_animation_create_layer_frame(text_layer_get_layer(s_date_layer), &s_date_grect_a, &s_date_grect_b); PropertyAnimation *date_center_prop = property_animation_create_layer_frame(text_layer_get_layer(s_date_layer), &s_date_grect_a, &s_date_grect_b);
@@ -186,71 +231,19 @@ static void update_minute_1() {
s_bt_grect_a = s_bt_grect_b; s_bt_grect_a = s_bt_grect_b;
} }
// DEBUG memory usage layer // animate swaps on half-hour boundaries (but not on first tick)
// static char s_memory_buffer[32]; if (units_changed & MINUTE_UNIT) {
// snprintf(s_memory_buffer, sizeof(s_memory_buffer), "%d/%d", (int)heap_bytes_used(), (int)heap_bytes_free() + (int)heap_bytes_used()); // ignore repeated callbacks for a minute that was already swapped: a duplicate
// text_layer_set_text(s_memory_layer, s_memory_buffer); // tick or a clock correction can move the clock back onto :00/:30
} if (!is_same_minute(tick_time, &s_last_swap_time)) {
if (tick_time->tm_min == 0) {
static void schedule_guy_animation(Animation *raise_tmpl, Animation *out_tmpl, Animation *in_tmpl, AnimationStoppedHandler out_handler) { s_last_swap_time = *tick_time;
Animation *raise = animation_clone(raise_tmpl); schedule_guy_animation(s_head_raise_template, s_head_out_template, s_head_in_template, update_minute_60_out_handler);
Animation *out = animation_clone(out_tmpl); } else if (tick_time->tm_min == 30) {
animation_set_handlers(out, (AnimationHandlers){.stopped = out_handler}, NULL); s_last_swap_time = *tick_time;
Animation *in = animation_clone(in_tmpl); schedule_guy_animation(s_butt_raise_template, s_butt_out_template, s_butt_in_template, update_minute_30_out_handler);
Animation *rest = animation_clone(raise_tmpl); }
animation_set_reverse(rest, true); }
Animation *seq = animation_sequence_create(raise, out, in, rest, NULL);
// set the handler to destroy the sequence (and its children) when finished
animation_set_handlers(seq, (AnimationHandlers){.stopped = destroy_animation_handler}, NULL);
// run it
animation_schedule(seq);
}
static void update_minute_30_out_handler(Animation *animation, bool finished, void *context) {
// destroy and reassign
gbitmap_destroy(s_butt);
s_butt_index = rand() % s_butt_count;
s_butt = gbitmap_create_with_resource(s_random_butts[s_butt_index]);
// swap colors
replace_gbitmap_color(GColorGreen, s_random_color_next, s_butt, NULL);
replace_gbitmap_color(s_random_color_current, s_random_color_next, s_head, NULL);
s_random_color_current = s_random_color_next;
s_random_color_next = s_dark_bg_colors[rand() % s_color_count];
// force update bitmap layers
bitmap_layer_set_bitmap(s_guy_butt_layer, s_butt);
bitmap_layer_set_bitmap(s_guy_head_layer, s_head);
}
static void update_minute_60_out_handler(Animation *animation, bool finished, void *context) {
// destroy and reassign
gbitmap_destroy(s_head);
s_head_index = rand() % s_head_count;
s_head = gbitmap_create_with_resource(s_random_heads[s_head_index]);
// swap colors
replace_gbitmap_color(GColorGreen, s_random_color_next, s_head, NULL);
replace_gbitmap_color(s_random_color_current, s_random_color_next, s_butt, NULL);
s_random_color_current = s_random_color_next;
s_random_color_next = s_dark_bg_colors[rand() % s_color_count];
// force update bitmap layers
bitmap_layer_set_bitmap(s_guy_head_layer, s_head);
bitmap_layer_set_bitmap(s_guy_butt_layer, s_butt);
}
static void minute_handler(struct tm *tick_time, TimeUnits units_changed) {
update_minute_1();
if (!s_first_tick_occurred) {
s_first_tick_occurred = true;
return; // do not animate part swaps on first tick
}
if (tick_time->tm_min % 60 == 0) {
schedule_guy_animation(s_head_raise_template, s_head_out_template, s_head_in_template, update_minute_60_out_handler);
} else if (tick_time->tm_min % 30 == 0) {
schedule_guy_animation(s_butt_raise_template, s_butt_out_template, s_butt_in_template, update_minute_30_out_handler);
} }
} }
@@ -284,9 +277,6 @@ static void main_window_load(Window *window) {
layer_add_child(window_layer, text_layer_get_layer(s_date_layer)); layer_add_child(window_layer, text_layer_get_layer(s_date_layer));
layer_add_child(window_layer, bitmap_layer_get_layer(s_bt_layer)); layer_add_child(window_layer, bitmap_layer_get_layer(s_bt_layer));
// DEBUG memory usage layer
// layer_add_child(window_layer, text_layer_get_layer(s_memory_layer));
// create animation templates // create animation templates
//// butt raise //// butt raise
PropertyAnimation *butt_raise_prop = property_animation_create_layer_frame(bitmap_layer_get_layer(s_guy_butt_layer), &s_guy_butt_grect_a, &s_guy_butt_grect_b); PropertyAnimation *butt_raise_prop = property_animation_create_layer_frame(bitmap_layer_get_layer(s_guy_butt_layer), &s_guy_butt_grect_a, &s_guy_butt_grect_b);
@@ -327,11 +317,13 @@ static void main_window_unload(Window *window) {
bitmap_layer_destroy(s_guy_butt_layer); bitmap_layer_destroy(s_guy_butt_layer);
layer_destroy(s_time_bar_layer); layer_destroy(s_time_bar_layer);
// Destroy animation templates // destroy animation templates
animation_destroy(s_butt_raise_template); animation_destroy(s_butt_raise_template);
animation_destroy(s_butt_out_template); animation_destroy(s_butt_out_template);
animation_destroy(s_butt_in_template);
animation_destroy(s_head_raise_template); animation_destroy(s_head_raise_template);
animation_destroy(s_head_out_template); animation_destroy(s_head_out_template);
animation_destroy(s_head_in_template);
} }
static void bluetooth_callback(bool connected) { static void bluetooth_callback(bool connected) {
@@ -342,24 +334,6 @@ static void bluetooth_callback(bool connected) {
} }
} }
// DEBUG buttons
// static void up_single_click_handler(ClickRecognizerRef recognizer, void *context) {
// Window *window = (Window *)context;
// schedule_guy_animation(s_head_raise_template, s_head_out_template, s_head_in_template, update_minute_60_out_handler);
//}
// DEBUG buttons
// static void down_single_click_handler(ClickRecognizerRef recognizer, void *context) {
// Window *window = (Window *)context;
// schedule_guy_animation(s_butt_raise_template, s_butt_out_template, s_butt_in_template, update_minute_30_out_handler);
//}
// DEBUG buttons
// static void click_config_provider(Window *window) {
// window_single_click_subscribe(BUTTON_ID_UP, up_single_click_handler);
// window_single_click_subscribe(BUTTON_ID_DOWN, down_single_click_handler);
//}
// set up the app on launch (don't put app logic in here); // set up the app on launch (don't put app logic in here);
static void init() { static void init() {
// seed RNG // seed RNG
@@ -397,8 +371,8 @@ static void init() {
// set starting colors // set starting colors
s_random_color_next = s_dark_bg_colors[rand() % s_color_count]; s_random_color_next = s_dark_bg_colors[rand() % s_color_count];
replace_gbitmap_color(GColorGreen, s_random_color_current, s_head, NULL); replace_gbitmap_color(GColorGreen, s_random_color_current, s_head);
replace_gbitmap_color(GColorGreen, s_random_color_current, s_butt, NULL); replace_gbitmap_color(GColorGreen, s_random_color_current, s_butt);
// load custom font // load custom font
#if PBL_DISPLAY_WIDTH <= 180 #if PBL_DISPLAY_WIDTH <= 180
@@ -450,16 +424,7 @@ static void init() {
s_bt_layer = bitmap_layer_create(s_bt_grect_a); s_bt_layer = bitmap_layer_create(s_bt_grect_a);
bitmap_layer_set_compositing_mode(s_bt_layer, GCompOpSet); bitmap_layer_set_compositing_mode(s_bt_layer, GCompOpSet);
bitmap_layer_set_alignment(s_bt_layer, GAlignCenter); bitmap_layer_set_alignment(s_bt_layer, GAlignCenter);
//// DEBUG memory usage layer
// s_memory_layer = text_layer_create(GRect(0, PBL_DISPLAY_HEIGHT - 24, PBL_DISPLAY_WIDTH, 14));
// text_layer_set_background_color(s_memory_layer, GColorClear);
// text_layer_set_font(s_memory_layer, fonts_get_system_font(FONT_KEY_GOTHIC_14));
// text_layer_set_text_color(s_memory_layer, GColorWhite);
// PBL_IF_ROUND_ELSE(text_layer_set_text_alignment(s_memory_layer, GTextAlignmentCenter), text_layer_set_text_alignment(s_memory_layer, GTextAlignmentLeft));
// make sure the time is displayed from the start
// and that the date/bt indicators are centered
update_minute_1();
//// register with ConnectionService (bluetooth status) //// register with ConnectionService (bluetooth status)
connection_service_subscribe((ConnectionHandlers){.pebble_app_connection_handler = bluetooth_callback}); connection_service_subscribe((ConnectionHandlers){.pebble_app_connection_handler = bluetooth_callback});
//// force a check to display correct bt indicator to start //// force a check to display correct bt indicator to start
@@ -473,39 +438,22 @@ static void init() {
// register with TickTimerService // register with TickTimerService
tick_timer_service_subscribe(MINUTE_UNIT, minute_handler); tick_timer_service_subscribe(MINUTE_UNIT, minute_handler);
// DEBUG buttons
// window_set_click_config_provider(s_main_window, (ClickConfigProvider)click_config_provider);
} }
// free memory on app exit // free memory on app exit
static void deinit() { static void deinit() {
// unsubscribe
tick_timer_service_unsubscribe(); tick_timer_service_unsubscribe();
// destroy layers
text_layer_destroy(s_time_layer); text_layer_destroy(s_time_layer);
text_layer_destroy(s_date_layer); text_layer_destroy(s_date_layer);
bitmap_layer_destroy(s_bt_layer); bitmap_layer_destroy(s_bt_layer);
// DEBUG memory usage layer
// text_layer_destroy(s_memory_layer);
// unload font
fonts_unload_custom_font(s_custom_font); fonts_unload_custom_font(s_custom_font);
// destroy gbitmaps
gbitmap_destroy(s_head); gbitmap_destroy(s_head);
gbitmap_destroy(s_butt); gbitmap_destroy(s_butt);
gbitmap_destroy(s_bt0_icon); gbitmap_destroy(s_bt0_icon);
gbitmap_destroy(s_bt1_icon); gbitmap_destroy(s_bt1_icon);
// write to persistent storage
persist_write_int(storage_key_head, s_head_index); persist_write_int(storage_key_head, s_head_index);
persist_write_int(storage_key_butt, s_butt_index); persist_write_int(storage_key_butt, s_butt_index);
persist_write_int(storage_key_color, s_random_color_current.argb); persist_write_int(storage_key_color, s_random_color_current.argb);
// destroy window
window_destroy(s_main_window); window_destroy(s_main_window);
} }
+2 -12
View File
@@ -2,8 +2,6 @@
#include "palette_manip.h" #include "palette_manip.h"
#ifdef PBL_COLOR
int get_num_palette_colors(GBitmap *b){ int get_num_palette_colors(GBitmap *b){
GBitmapFormat format = gbitmap_get_format(b); GBitmapFormat format = gbitmap_get_format(b);
switch (format) { switch (format) {
@@ -16,7 +14,7 @@ int get_num_palette_colors(GBitmap *b){
} }
} }
void replace_gbitmap_color(GColor color_to_replace, GColor replace_with_color, GBitmap *im, BitmapLayer *bml){ void replace_gbitmap_color(GColor color_to_replace, GColor replace_with_color, GBitmap *im){
//First determine what the number of colors in the palette //First determine what the number of colors in the palette
int num_palette_items = get_num_palette_colors(im); int num_palette_items = get_num_palette_colors(im);
@@ -30,12 +28,4 @@ void replace_gbitmap_color(GColor color_to_replace, GColor replace_with_color, G
current_palette[i].argb = (current_palette[i].argb & 0xC0)| (replace_with_color.argb & 0x3F); current_palette[i].argb = (current_palette[i].argb & 0xC0)| (replace_with_color.argb & 0x3F);
} }
} }
}
//Mark the bitmaplayer dirty
if(bml != NULL){
layer_mark_dirty(bitmap_layer_get_layer(bml));
}
}
#endif
+1 -1
View File
@@ -3,5 +3,5 @@
#include <pebble.h> #include <pebble.h>
#ifdef PBL_COLOR #ifdef PBL_COLOR
void replace_gbitmap_color(GColor color_to_replace, GColor replace_with_color, GBitmap *im, BitmapLayer *bml); void replace_gbitmap_color(GColor color_to_replace, GColor replace_with_color, GBitmap *im);
#endif #endif
-18
View File
@@ -1,18 +0,0 @@
#!/usr/bin/env zsh
echo "CompileFlags:
Add:
[
-DPBL_DISPLAY_WIDTH=200,
-DPBL_DISPLAY_HEIGHT=228,
-xc,
-nostdinc,
-DPBL_COLOR,
-I${HOME}/.pebble-sdk/SDKs/current/sdk-core/pebble/emery/include,
-include/home/cuan/gitrepos/Maan-On-My-Wrist-XL/build/include/message_keys.auto.h,
-I$(pwd)/build/emery,
-include${HOME}/.pebble-sdk/SDKs/current/toolchain/arm-none-eabi/arm-none-eabi/include/stdint.h,
-include${HOME}/.pebble-sdk/SDKs/current/toolchain/arm-none-eabi/arm-none-eabi/include/stdlib.h,
-include${HOME}/.pebble-sdk/SDKs/current/toolchain/arm-none-eabi/arm-none-eabi/include/time.h,
-include${HOME}/.pebble-sdk/SDKs/current/toolchain/arm-none-eabi/lib/gcc/arm-none-eabi/14.2.1/include/stddef.h,
-include${HOME}/.pebble-sdk/SDKs/current/toolchain/arm-none-eabi/lib/gcc/arm-none-eabi/14.2.1/include/stdbool.h,
]" > ./.clangd
-33
View File
@@ -1,33 +0,0 @@
#!/usr/bin/env zsh
# THIS IS A LEGACY TOOL THAT WAS USED FOR THE INITIAL
# ASSET EXTRACTION - ASSETS HAVE SINCE BEEN HEAVILY
# MODIFIED, MAKING THIS SCRIPT PRETTY USELESS
if [[ $# -lt 2 ]]; then
echo "Usage: $0 <dir> <half (top/bottom)>"
exit 1
fi
if [[ $2 == "top" ]]; then
gravity="South"
elif [[ $2 == "bottom" ]]; then
gravity="North"
else
echo "Usage: $0 <dir> <half (top/bottom)>"
exit 1
fi
for file in $1/*; do
magick "$file" -gravity $gravity -chop 0x10 "$file"
magick "$file" -transparent Black PNG24:"$file"
magick "$file" -fill "rgb(0,255,0)" -opaque White "$file"
magick "$file" -gravity Center -background None -compose Copy -extent 260x $file
# Bar is commented out for an experiment with rendering in real time on the watch
#magick "$file" -gravity $gravity -background White -splice 0x15 $file
if [[ $2 == "top" ]]; then
magick "$file" -gravity North -background None -splice 0x41 $file
else
magick "$file" -gravity South -background None -splice 0x41 $file
fi
done
-7
View File
@@ -1,7 +0,0 @@
#!/usr/bin/env zsh
# ALWAYS USE ZOPFLI TO CRUSH PNGS AS MUCH AS POSSIBLE BEFORE SHIPPING
for file in **/*; do
zopflipng -y --iterations=500 --filters=01234mepb --lossy_8bit --lossy_transparent $file $file &
done