Skip to content

Commit 5990df3

Browse files
authored
Merge pull request #19 from vani-tty1/unstable
feat: new black and white filter
2 parents 02326e1 + 04a436e commit 5990df3

8 files changed

Lines changed: 100 additions & 22 deletions

File tree

‎src/meme-core.c‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,24 @@ GdkPixbuf *meme_core_apply_deep_fry(GdkPixbuf *src) {
113113
return out;
114114
}
115115

116+
117+
GdkPixbuf *
118+
meme_core_apply_black_and_white(GdkPixbuf *src)
119+
{
120+
MagickWand *wand;
121+
GdkPixbuf *out;
122+
123+
MagickWandGenesis();
124+
wand = pixbuf_to_wand(src);
125+
MagickModulateImage(wand, 100.0, 0.0, 100.0);
126+
out = wand_to_pixbuf(wand);
127+
DestroyMagickWand(wand);
128+
MagickWandTerminus();
129+
130+
return out;
131+
}
132+
133+
116134
GdkPixbuf *meme_core_apply_effects(GdkPixbuf *composite, gboolean cinematic, gboolean deep_fry) {
117135
GdkPixbuf *result;
118136
gboolean own;

‎src/meme-core.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,4 @@ void meme_layer_list_free (GList *list);
6565
GdkPixbuf *meme_core_apply_effects(GdkPixbuf *composite, gboolean cinematic, gboolean deep_fry);
6666
GdkPixbuf *meme_core_apply_saturation_contrast(GdkPixbuf *src, double sat, double contrast);
6767
GdkPixbuf *meme_core_apply_deep_fry(GdkPixbuf *src);
68+
GdkPixbuf *meme_core_apply_black_and_white (GdkPixbuf *src);

‎src/meme-fileio.c‎

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ typedef struct {
1111
GList *layers_copy;
1212
gboolean cinematic;
1313
gboolean deepfry;
14+
gboolean bw;
1415
} GifExportData;
1516
// async gif handling functions, fucking hell why is it so hard to do async
1617
// work
@@ -81,7 +82,7 @@ static void export_gif_thread(GTask *task, gpointer source_object, gpointer task
8182
}
8283

8384
delay_ms = MAX((int)MagickGetImageDelay(coalesced) * 10, 10);
84-
comp = meme_render_composite(frame, ctx->layers_copy, ctx->cinematic, ctx->deepfry, FALSE);
85+
comp = meme_render_composite(frame, ctx->layers_copy, ctx->cinematic, ctx->deepfry, ctx->bw, FALSE);
8586
w = gdk_pixbuf_get_width(comp);
8687
h = gdk_pixbuf_get_height(comp);
8788
channels = gdk_pixbuf_get_n_channels(comp);
@@ -346,6 +347,7 @@ static void on_project_load_contents_finished(GObject *source_object, GAsyncResu
346347
gtk_widget_set_sensitive(GTK_WIDGET(self->crop_mode_button), TRUE);
347348
gtk_widget_set_sensitive(GTK_WIDGET(self->save_project_button), TRUE);
348349
gtk_widget_set_sensitive(GTK_WIDGET(self->global_filters_button), TRUE);
350+
gtk_widget_set_sensitive(GTK_WIDGET(self->bw_button), TRUE);
349351
gtk_widget_set_sensitive(GTK_WIDGET(self->zoom_in), TRUE);
350352
gtk_widget_set_sensitive(GTK_WIDGET(self->zoom_out), TRUE);
351353
gtk_widget_set_sensitive(GTK_WIDGET(self->copy_clipboard_button), TRUE);
@@ -403,6 +405,7 @@ static void on_load_image_response(GObject *s, GAsyncResult *r, gpointer d) {
403405
gtk_widget_set_sensitive(GTK_WIDGET(self->add_image_button), TRUE);
404406
gtk_widget_set_sensitive(GTK_WIDGET(self->deep_fry_button), TRUE);
405407
gtk_widget_set_sensitive(GTK_WIDGET(self->cinematic_button), TRUE);
408+
gtk_widget_set_sensitive(GTK_WIDGET(self->bw_button), TRUE);
406409
gtk_widget_set_sensitive(GTK_WIDGET(self->crop_mode_button), TRUE);
407410
gtk_widget_set_sensitive(GTK_WIDGET(self->save_project_button), TRUE);
408411
gtk_widget_set_sensitive(GTK_WIDGET(self->global_filters_button), TRUE);
@@ -488,6 +491,7 @@ static void on_export_file_response(GObject *s, GAsyncResult *r, gpointer d) {
488491
data->layers_copy = meme_layer_list_copy(self->layers);
489492
data->cinematic = gtk_toggle_button_get_active(self->cinematic_button);
490493
data->deepfry = gtk_toggle_button_get_active(self->deep_fry_button);
494+
data->bw = gtk_toggle_button_get_active(self->bw_button);
491495

492496
task = g_task_new(self, NULL, on_gif_export_ready, self);
493497
g_task_set_task_data(task, data, gif_export_data_free);
@@ -538,26 +542,39 @@ static void on_export_file_response(GObject *s, GAsyncResult *r, gpointer d) {
538542
g_object_unref(file);
539543
}
540544

541-
static void on_format_chosen(GObject *s, GAsyncResult *r, gpointer d) {\
545+
static void on_format_chosen(GObject *s, GAsyncResult *r, gpointer d) {
542546
char *filename;
543547
GtkFileDialog *dialog;
544548
const char *ext;
549+
const char *format;
550+
GtkDropDown *format_dropdown;
551+
guint selected;
545552
AdwAlertDialog *alert = ADW_ALERT_DIALOG(s);
546553
MemeWindow *self = MEME_WINDOW(d);
547554
const char *choice = adw_alert_dialog_choose_finish(alert, r);
548555

549-
if (g_strcmp0(choice, "cancel") == 0 || !choice) return;
556+
if (g_strcmp0(choice, "export") != 0) return;
557+
558+
format_dropdown = GTK_DROP_DOWN(g_object_get_data(G_OBJECT(alert), "format-dropdown"));
559+
selected = gtk_drop_down_get_selected(format_dropdown);
560+
561+
switch (selected) {
562+
case 1: format = "jpeg"; break;
563+
case 2: format = "webp"; break;
564+
case 3: format = "gif"; break;
565+
default: format = "png"; break;
566+
}
550567

551568
ext = ".png";
552-
if (g_strcmp0(choice, "jpeg") == 0) ext = ".jpg";
553-
else if (g_strcmp0(choice, "webp") == 0) ext = ".webp";
554-
else if (g_strcmp0(choice, "gif") == 0) ext = ".gif";
569+
if (g_strcmp0(format, "jpeg") == 0) ext = ".jpg";
570+
else if (g_strcmp0(format, "webp") == 0) ext = ".webp";
571+
else if (g_strcmp0(format, "gif") == 0) ext = ".gif";
555572

556573
filename = g_strdup_printf("meme%s", ext);
557574
dialog = gtk_file_dialog_new();
558575
gtk_file_dialog_set_initial_name(dialog, filename);
559576

560-
g_object_set_data(G_OBJECT(dialog), "export-format", (gpointer)choice);
577+
g_object_set_data(G_OBJECT(dialog), "export-format", (gpointer)format);
561578

562579
gtk_file_dialog_save(dialog, GTK_WINDOW(self), NULL, on_export_file_response, self);
563580

@@ -567,19 +584,29 @@ static void on_format_chosen(GObject *s, GAsyncResult *r, gpointer d) {\
567584

568585
void on_export_clicked(MemeWindow *self) {
569586
AdwAlertDialog *dialog;
587+
GtkWidget *format_dropdown;
588+
GtkStringList *model;
589+
static const char *format_labels[] = { "PNG", "JPG", "WebP", "GIF", NULL };
570590

571591
if (!self->final_meme) return;
592+
593+
model = gtk_string_list_new(format_labels);
594+
format_dropdown = gtk_drop_down_new(G_LIST_MODEL(model), NULL);
595+
gtk_drop_down_set_selected(GTK_DROP_DOWN(format_dropdown), 0);
596+
572597
dialog = ADW_ALERT_DIALOG(adw_alert_dialog_new("Export Format", "Choose an image format."));
598+
adw_alert_dialog_set_extra_child(dialog, format_dropdown);
599+
g_object_set_data(G_OBJECT(dialog), "format-dropdown", format_dropdown);
600+
573601
adw_alert_dialog_add_responses(dialog,
574602
"cancel", "Cancel",
575-
"png", "PNG",
576-
"gif", "GIF",
577-
"jpeg", "JPG",
578-
"webp", "WebP",
603+
"export", "Export",
579604
NULL);
580605

581-
adw_alert_dialog_set_response_appearance(dialog, "png", ADW_RESPONSE_SUGGESTED);
606+
adw_alert_dialog_set_response_appearance(dialog, "export", ADW_RESPONSE_SUGGESTED);
582607
adw_alert_dialog_set_response_appearance(dialog, "cancel", ADW_RESPONSE_DESTRUCTIVE);
608+
adw_alert_dialog_set_default_response(dialog, "export");
609+
adw_alert_dialog_set_close_response(dialog, "cancel");
583610

584611
adw_alert_dialog_choose(dialog, GTK_WIDGET(self), NULL, on_format_chosen, self);
585612
}

‎src/meme-renderer.c‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,10 @@ static void meme_layer_ensure_text_pixbuf(ImageLayer *layer, int bg_width) {
217217
pango_font_description_free(desc);
218218
}
219219

220-
GdkPixbuf *meme_render_composite(GdkPixbuf *bg, GList *layers, gboolean cinematic, gboolean deep_fry, gboolean fast_mode) {
220+
GdkPixbuf *meme_render_composite(GdkPixbuf *bg, GList *layers,
221+
gboolean cinematic,
222+
gboolean deep_fry, gboolean bw,
223+
gboolean fast_mode) {
221224
GdkPixbuf *comp;
222225
int render_w;
223226
int render_h;
@@ -291,6 +294,12 @@ GdkPixbuf *meme_render_composite(GdkPixbuf *bg, GList *layers, gboolean cinemati
291294
comp = gdk_pixbuf_get_from_surface(surf, 0, 0, render_w, render_h);
292295
cairo_surface_destroy(surf);
293296

297+
if (bw) {
298+
GdkPixbuf *tmp = meme_core_apply_black_and_white(comp);
299+
g_object_unref(comp);
300+
comp = tmp;
301+
}
302+
294303
if (!fast_mode && (cinematic || deep_fry)) {
295304
GdkPixbuf *tmp = meme_core_apply_effects(comp, cinematic, deep_fry);
296305
if (tmp) {

‎src/meme-renderer.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ GdkPixbuf *meme_apply_saturation_contrast (GdkPixbuf *src, double sat, double co
88
GdkPixbuf *meme_apply_deep_fry (GdkPixbuf *src);
99

1010

11-
GdkPixbuf *meme_render_composite(GdkPixbuf *bg, GList *layers, gboolean cinematic, gboolean deep_fry, gboolean fast_mode);
11+
GdkPixbuf *meme_render_composite(GdkPixbuf *bg, GList *layers, gboolean cinematic, gboolean deep_fry, gboolean bw, gboolean fast_mode);
1212

1313
GdkTexture *meme_render_editor_overlay (GdkPixbuf *composite,
1414
GList *layers,

‎src/meme-window-private.h‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ struct _MemeWindow {
2424
GtkButton *export_button, *copy_clipboard_button, *zoom_in, *zoom_out;
2525
GtkButton *load_image_button, *pill_btn_open_image, *clear_button, *add_image_button;
2626
GtkButton *import_template_button, *delete_template_button;
27-
GtkToggleButton *deep_fry_button, *cinematic_button, *crop_mode_button;
27+
GtkToggleButton *deep_fry_button, *cinematic_button, *crop_mode_button, *bw_button;
2828
GtkFlowBox *template_gallery;
2929
GtkMenuButton *global_filters_button;
3030
GtkScale *layer_opacity_scale, *layer_rotation_scale;
@@ -56,7 +56,7 @@ struct _MemeWindow {
5656
GtkButton *footer_add_image_button, *footer_add_text_button;
5757
GtkButton *footer_copy_clipboard_button, *footer_delete_layer_button;
5858
GtkButton *footer_zoom_in, *footer_zoom_out, *footer_clear_button;
59-
GtkToggleButton *footer_crop_mode_button, *footer_cinematic_button, *footer_deep_fry_button;
59+
GtkToggleButton *footer_crop_mode_button, *footer_cinematic_button, *footer_deep_fry_button, *footer_bw_button;
6060
GtkMenuButton *footer_global_filters_button;
6161
GtkButton *footer_rotate_left_button;
6262
GtkButton *footer_rotate_right_button;

‎src/meme-window.blp‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,14 @@ template $MemeWindow: Adw.ApplicationWindow {
220220
"destructive-action",
221221
]
222222
}
223+
224+
ToggleButton footer_bw_button {
225+
label: _("Black & White");
226+
tooltip-text: _("Make it old school");
227+
icon-name: "preferences-color-symbolic";
228+
sensitive: bind bw_button.sensitive;
229+
active: bind bw_button.active bidirectional;
230+
}
223231
}
224232
};
225233
}
@@ -616,6 +624,13 @@ template $MemeWindow: Adw.ApplicationWindow {
616624
"destructive-action",
617625
]
618626
}
627+
628+
ToggleButton bw_button {
629+
label: _("Black & White");
630+
tooltip-text: _("Black and White");
631+
icon-name: "preferences-color-symbolic";
632+
sensitive: false;
633+
}
619634
}
620635
};
621636
}

‎src/meme-window.c‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ G_DEFINE_FINAL_TYPE (MemeWindow, meme_window, ADW_TYPE_APPLICATION_WINDOW)
3434
static void populate_template_gallery (MemeWindow *self);
3535

3636
void render_meme (MemeWindow *self) {
37-
gboolean is_dragging, is_crop_drag, cinematic, deepfry;
37+
gboolean is_dragging, is_crop_drag, cinematic, deepfry, bw_button;
3838
GdkTexture *tex;
3939

4040
if (!self->template_image) return;
@@ -44,14 +44,16 @@ void render_meme (MemeWindow *self) {
4444
self->drag_type == DRAG_TYPE_CROP_RESIZE);
4545
cinematic = gtk_toggle_button_get_active(self->cinematic_button);
4646
deepfry = gtk_toggle_button_get_active(self->deep_fry_button);
47+
bw_button = gtk_toggle_button_get_active(self->bw_button);
4748

4849
if (!self->final_meme || !is_crop_drag) {
4950
if (self->final_meme) g_object_unref(self->final_meme);
5051
self->final_meme = meme_render_composite(self->template_image,
51-
self->layers,
52-
cinematic,
53-
deepfry,
54-
is_dragging);
52+
self->layers,
53+
cinematic,
54+
deepfry,
55+
bw_button,
56+
is_dragging);
5557
}
5658
gtk_widget_queue_draw(GTK_WIDGET(self->meme_preview));
5759
if (is_dragging && !is_crop_drag) {
@@ -402,6 +404,8 @@ void on_clear_clicked (MemeWindow *self) {
402404
gtk_widget_set_sensitive(GTK_WIDGET(self->zoom_in), FALSE);
403405
gtk_widget_set_sensitive(GTK_WIDGET(self->zoom_out), FALSE);
404406
gtk_widget_set_sensitive(GTK_WIDGET(self->copy_clipboard_button), FALSE);
407+
gtk_toggle_button_set_active (self->bw_button, FALSE);
408+
gtk_widget_set_sensitive(GTK_WIDGET(self->bw_button), FALSE);
405409
self->zoom_level = 1.0;
406410
gtk_widget_set_size_request(GTK_WIDGET(self->meme_preview), -1, -1);
407411
}
@@ -604,6 +608,7 @@ static void on_template_selected (GtkFlowBox *flowbox, GtkFlowBoxChild *child, M
604608
gtk_widget_set_sensitive (GTK_WIDGET (self->add_image_button), TRUE);
605609
gtk_widget_set_sensitive (GTK_WIDGET (self->deep_fry_button), TRUE);
606610
gtk_widget_set_sensitive (GTK_WIDGET (self->cinematic_button), TRUE);
611+
gtk_widget_set_sensitive (GTK_WIDGET (self->bw_button), TRUE);
607612
gtk_widget_set_sensitive(GTK_WIDGET(self->crop_mode_button), TRUE);
608613
gtk_widget_set_sensitive(GTK_WIDGET(self->save_project_button), TRUE);
609614
gtk_widget_set_sensitive(GTK_WIDGET(self->global_filters_button), TRUE);
@@ -790,6 +795,7 @@ static void meme_window_class_init (MemeWindowClass *klass) {
790795
gtk_widget_class_bind_template_child (widget_class, MemeWindow, deep_fry_button);
791796
gtk_widget_class_bind_template_child (widget_class, MemeWindow, template_gallery);
792797
gtk_widget_class_bind_template_child (widget_class, MemeWindow, cinematic_button);
798+
gtk_widget_class_bind_template_child (widget_class, MemeWindow, bw_button);
793799
gtk_widget_class_bind_template_child (widget_class, MemeWindow, layer_opacity_scale);
794800
gtk_widget_class_bind_template_child (widget_class, MemeWindow, layer_rotation_scale);
795801
gtk_widget_class_bind_template_child (widget_class, MemeWindow, blend_mode_row);
@@ -847,6 +853,7 @@ static void meme_window_class_init (MemeWindowClass *klass) {
847853
gtk_widget_class_bind_template_child (widget_class, MemeWindow, footer_layer_font_size);
848854
gtk_widget_class_bind_template_child (widget_class, MemeWindow, footer_text_delete_button);
849855
gtk_widget_class_bind_template_child (widget_class, MemeWindow, footer_exit_text_button);
856+
gtk_widget_class_bind_template_child (widget_class, MemeWindow, footer_bw_button);
850857
}
851858

852859
static void meme_window_init (MemeWindow *self) {
@@ -933,7 +940,8 @@ static void meme_window_init (MemeWindow *self) {
933940

934941
g_signal_connect_swapped (self->footer_text_delete_button, "clicked", G_CALLBACK (on_delete_layer_clicked), self);
935942
g_signal_connect_swapped (self->footer_exit_text_button, "clicked", G_CALLBACK (on_exit_text_editing_clicked), self);
936-
943+
g_signal_connect (self->bw_button, "toggled", G_CALLBACK (on_deep_fry_toggled), self);
944+
g_signal_connect (self->footer_bw_button, "toggled", G_CALLBACK (on_deep_fry_toggled), self);
937945
populate_template_gallery (self);
938946

939947
motion = gtk_event_controller_motion_new ();

0 commit comments

Comments
 (0)