Resize all images that are part of a notebook

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Resize all images that are part of a notebook

Gtk+ - General mailing list
Greetings,
I am trying to create a program that has a notebook with several images. I want to be
able to grab the corner of the window and expand or contract the image size,
maintaining aspect ratio of any image on any notebook page. The following is my latest attempt. However, this program auto increases in size and the user has no 
control. Someone attempting to try this would need two images in the folder with the
executable, image1.jpg and image2.jpg.
Compile with GTK3 libs.
Thanks,
Jack

#include <stdio.h>
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>

GtkWidget *notebook;

gboolean resize_image(GtkWidget *widget, GdkRectangle *allocation,
gpointer user_data)
{
int w,h, pagenum;
GdkPixbuf *pxbscaled;
GtkWidget *image;
GdkPixbuf *pixbuf;

pagenum = gtk_notebook_get_current_page (GTK_NOTEBOOK(notebook));
image = gtk_notebook_get_nth_page (GTK_NOTEBOOK(notebook), pagenum);
// GtkImageType image_type = gtk_image_get_storage_type
// (GTK_IMAGE(image));

pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(image));

h = allocation->height;
w = (gdk_pixbuf_get_width(pixbuf) * h) / gdk_pixbuf_get_height(pixbuf);

pxbscaled = gdk_pixbuf_scale_simple(pixbuf, w, h, GDK_INTERP_BILINEAR);

printf("Allocation height %d width %d.\n", h, w);

gtk_image_set_from_pixbuf(GTK_IMAGE(image), pxbscaled);

g_object_unref (pxbscaled);

sleep(2);

return FALSE;
}

static gboolean delete( GtkWidget *widget,
GtkWidget *event,
gpointer   data )
{
gtk_main_quit ();
return FALSE;
}

int main( int argc,
  char *argv[] )
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *table;
GtkWidget *label;
GtkWidget *image;
int i;
char bufferl[32];

gtk_init (&argc, &argv);

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
// gtk_widget_set_size_request (GTK_WIDGET(window), 800, 480);

g_signal_connect (window, "delete-event",
  G_CALLBACK (delete), NULL);

gtk_container_set_border_width (GTK_CONTAINER (window), 10);

table = gtk_grid_new ();
gtk_container_add (GTK_CONTAINER (window), table);

/* Create notebook, place position of tabs */
notebook = gtk_notebook_new ();
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
gtk_grid_attach (GTK_GRID (table), notebook, 0, 6, 3, 3);
gtk_widget_show (notebook);

/* Append pages to the notebook */
for (i = 0; i < 2; i++) {
sprintf(bufferl, "Page %d", i + 1);

if (i == 0) {
image = gtk_image_new_from_file("image1.jpg");
} else {
image = gtk_image_new_from_file("image2.jpg");
}

gtk_widget_set_halign(image, GTK_ALIGN_START);
gtk_widget_set_valign(image, GTK_ALIGN_START);

g_signal_connect(window, "size-allocate", 
G_CALLBACK(resize_image), NULL);

label = gtk_label_new (bufferl);
gtk_notebook_append_page (GTK_NOTEBOOK(notebook), 
image, label);
}

/* Create a close button */
button = gtk_button_new_with_label ("close");
g_signal_connect (button, "clicked",
  G_CALLBACK (delete), NULL);

gtk_grid_attach (GTK_GRID (table), button, 0, 10, 1, 1);

gtk_widget_show_all (window);

gtk_main ();

return 0;
}


_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|

Re: Resize all images that are part of a notebook

Gtk+ - General mailing list

Hi Jack,

There are some problem spots in your code. There is a

g_signal_connect(window, "size-allocate", G_CALLBACK(resize_image), NULL);

in a loop and the resize_image function doesn't match the documentation.

https://developer.gnome.org/gtk3/stable/GtkWidget.html#GtkWidget-size-allocate

Careful with this because GTK doesn't always warn if you get your callbacks setup incorrectly. Then you might end up with some weird bugs that are hard to find in your code. You can change the names of the parameters in the callback but you need to keep the parameter types, number of parameters and return value the same as in the documentation.

There is a sleep(2) that you don't need in there.

g_strdup_printf() is safer and easier to use than sprintf with a buffer.

I am not sure how you want to have the images resized. If you want to have them resized with the main window that can be done. It is best if you get a pixbuf and keep it around so you can always resize the "original". This helps with reducing pixel loss. You could also use a drawing area, draw a frame in it and use that to drag and reduce or enlarge an image.

I gave it a try and may have a few mistakes myself. Maybe between the two you can figure out a good working solution.

Eric


/*
    gcc -Wall image1.c -o image1 `pkg-config gtk+-3.0 --cflags --libs`

    Tested on Ubuntu16.04 with GTK3.18.
*/

#include<gtk/gtk.h>

static void resize_image1(GtkWidget *scroll1, GdkRectangle *allocation, gpointer *data1)
  {
    g_print("Resize1\n");
    gdouble width=(gdouble)gdk_pixbuf_get_width((GdkPixbuf*)data1[1]);
    gdouble height=(gdouble)gdk_pixbuf_get_height((GdkPixbuf*)data1[1]);
    gdouble new_width=(gdouble)allocation->width;
    gdouble new_height=new_width/(width/height);

    if(new_height>(allocation->height))
      {
        new_height=(gdouble)allocation->height;
        new_width=new_height/(height/width);
      }

    GdkPixbuf *pxbscaled=gdk_pixbuf_scale_simple((GdkPixbuf*)data1[1], (gint)new_width, (gint)new_height, GDK_INTERP_BILINEAR);
    gtk_image_set_from_pixbuf(GTK_IMAGE(data1[0]), pxbscaled);
    g_object_unref(pxbscaled);
  }
static void resize_image2(GtkWidget *scroll, GdkRectangle *allocation, gpointer *data2)
  {
    g_print("Resize2\n");
    gdouble width=(gdouble)gdk_pixbuf_get_width((GdkPixbuf*)data2[1]);
    gdouble height=(gdouble)gdk_pixbuf_get_height((GdkPixbuf*)data2[1]);
    gdouble new_width=(gdouble)allocation->width;
    gdouble new_height=new_width/(width/height);

    if(new_height>(allocation->height))
      {
        new_height=(gdouble)allocation->height;
        new_width=new_height/(height/width);
      }

    GdkPixbuf *pxbscaled=gdk_pixbuf_scale_simple((GdkPixbuf*)data2[1], (gint)new_width, (gint)new_height, GDK_INTERP_BILINEAR);
    gtk_image_set_from_pixbuf(GTK_IMAGE(data2[0]), pxbscaled);
    g_object_unref(pxbscaled);
  }
int main(int argc, char *argv[])
  {
    gtk_init(&argc, &argv);

    GtkWidget *window=gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Notebook");
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 500);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    GdkPixbuf *pixbuf1=gdk_pixbuf_new_from_file_at_scale("image1.jpg", 500, 500, TRUE, NULL);
    GdkPixbuf *pixbuf2=gdk_pixbuf_new_from_file_at_scale("image2.jpg", 500, 500, TRUE, NULL);
   
    GtkWidget *image1=gtk_image_new_from_pixbuf(pixbuf1);
    gtk_widget_set_hexpand(image1, TRUE);
    gtk_widget_set_vexpand(image1, TRUE);

    GtkWidget *scroll1=gtk_scrolled_window_new(NULL, NULL);
    gtk_container_add(GTK_CONTAINER(scroll1), image1);
    gpointer data1[]={image1, pixbuf1};
    g_signal_connect(scroll1, "size-allocate", G_CALLBACK(resize_image1), data1);
  
    GtkWidget *grid1=gtk_grid_new();
    gtk_grid_attach(GTK_GRID(grid1), scroll1, 0, 0, 1, 1);   
   
    GtkWidget *image2=gtk_image_new_from_pixbuf(pixbuf2);
    gtk_widget_set_hexpand(image2, TRUE);
    gtk_widget_set_vexpand(image2, TRUE);

    GtkWidget *scroll2=gtk_scrolled_window_new(NULL, NULL);
    gtk_container_add(GTK_CONTAINER(scroll2), image2);
    gpointer data2[]={image2, pixbuf2};
    g_signal_connect(scroll2, "size-allocate", G_CALLBACK(resize_image2), data2);
   
    GtkWidget *grid2=gtk_grid_new();
    gtk_grid_attach(GTK_GRID(grid2), scroll2, 0, 0, 1, 1);

    GtkWidget *nb_label1=gtk_label_new("Page 1");
    GtkWidget *nb_label2=gtk_label_new("Page 2");
    GtkWidget *notebook=gtk_notebook_new();
    gtk_container_set_border_width(GTK_CONTAINER(notebook), 15);
    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), grid1, nb_label1);
    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), grid2, nb_label2);

    gtk_container_add(GTK_CONTAINER(window), notebook);

    gtk_widget_show_all(window);

    gtk_main();

    g_object_unref(pixbuf1);
    g_object_unref(pixbuf2);

    return 0;
  }



_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|

Re: Resize all images that are part of a notebook

Gtk+ - General mailing list
Thanks, Eric. 

I must have arrived at my "fix" the same time you came up with your much more elegant fix.
I did remove the sleep call. But my only other change was to change the line in the call back
from 
h = allocation->height;
to 
h = allocation->height * 0.75;

I realized I was resizing the image to the size of the entire window, which would trigger another resize, and another....etc.
Limiting to height to 3/4 of the window stops it from growing out of control. But the image degrades quickly.

But seeing your code with two call backs makes me think I need to try gtkmm, as I actually need 7 images in a notebook.
If I could make a class with the resize defined, I would not need 7 nearly identical callback routines.

On Thu, Aug 2, 2018 at 11:25 AM, <[hidden email]> wrote:

Hi Jack,

There are some problem spots in your code. There is a

g_signal_connect(window, "size-allocate", G_CALLBACK(resize_image), NULL);

in a loop and the resize_image function doesn't match the documentation.

https://developer.gnome.org/gtk3/stable/GtkWidget.html#GtkWidget-size-allocate

Careful with this because GTK doesn't always warn if you get your callbacks setup incorrectly. Then you might end up with some weird bugs that are hard to find in your code. You can change the names of the parameters in the callback but you need to keep the parameter types, number of parameters and return value the same as in the documentation.

There is a sleep(2) that you don't need in there.

g_strdup_printf() is safer and easier to use than sprintf with a buffer.

I am not sure how you want to have the images resized. If you want to have them resized with the main window that can be done. It is best if you get a pixbuf and keep it around so you can always resize the "original". This helps with reducing pixel loss. You could also use a drawing area, draw a frame in it and use that to drag and reduce or enlarge an image.

I gave it a try and may have a few mistakes myself. Maybe between the two you can figure out a good working solution.

Eric


/*
    gcc -Wall image1.c -o image1 `pkg-config gtk+-3.0 --cflags --libs`

    Tested on Ubuntu16.04 with GTK3.18.
*/

#include<gtk/gtk.h>

static void resize_image1(GtkWidget *scroll1, GdkRectangle *allocation, gpointer *data1)
  {
    g_print("Resize1\n");
    gdouble width=(gdouble)gdk_pixbuf_get_width((GdkPixbuf*)data1[1]);
    gdouble height=(gdouble)gdk_pixbuf_get_height((GdkPixbuf*)data1[1]);
    gdouble new_width=(gdouble)allocation->width;
    gdouble new_height=new_width/(width/height);

    if(new_height>(allocation->height))
      {
        new_height=(gdouble)allocation->height;
        new_width=new_height/(height/width);
      }

    GdkPixbuf *pxbscaled=gdk_pixbuf_scale_simple((GdkPixbuf*)data1[1], (gint)new_width, (gint)new_height, GDK_INTERP_BILINEAR);
    gtk_image_set_from_pixbuf(GTK_IMAGE(data1[0]), pxbscaled);
    g_object_unref(pxbscaled);
  }
static void resize_image2(GtkWidget *scroll, GdkRectangle *allocation, gpointer *data2)
  {
    g_print("Resize2\n");
    gdouble width=(gdouble)gdk_pixbuf_get_width((GdkPixbuf*)data2[1]);
    gdouble height=(gdouble)gdk_pixbuf_get_height((GdkPixbuf*)data2[1]);
    gdouble new_width=(gdouble)allocation->width;
    gdouble new_height=new_width/(width/height);

    if(new_height>(allocation->height))
      {
        new_height=(gdouble)allocation->height;
        new_width=new_height/(height/width);
      }

    GdkPixbuf *pxbscaled=gdk_pixbuf_scale_simple((GdkPixbuf*)data2[1], (gint)new_width, (gint)new_height, GDK_INTERP_BILINEAR);
    gtk_image_set_from_pixbuf(GTK_IMAGE(data2[0]), pxbscaled);
    g_object_unref(pxbscaled);
  }
int main(int argc, char *argv[])
  {
    gtk_init(&argc, &argv);

    GtkWidget *window=gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Notebook");
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 500);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    GdkPixbuf *pixbuf1=gdk_pixbuf_new_from_file_at_scale("image1.jpg", 500, 500, TRUE, NULL);
    GdkPixbuf *pixbuf2=gdk_pixbuf_new_from_file_at_scale("image2.jpg", 500, 500, TRUE, NULL);
   
    GtkWidget *image1=gtk_image_new_from_pixbuf(pixbuf1);
    gtk_widget_set_hexpand(image1, TRUE);
    gtk_widget_set_vexpand(image1, TRUE);

    GtkWidget *scroll1=gtk_scrolled_window_new(NULL, NULL);
    gtk_container_add(GTK_CONTAINER(scroll1), image1);
    gpointer data1[]={image1, pixbuf1};
    g_signal_connect(scroll1, "size-allocate", G_CALLBACK(resize_image1), data1);
  
    GtkWidget *grid1=gtk_grid_new();
    gtk_grid_attach(GTK_GRID(grid1), scroll1, 0, 0, 1, 1);   
   
    GtkWidget *image2=gtk_image_new_from_pixbuf(pixbuf2);
    gtk_widget_set_hexpand(image2, TRUE);
    gtk_widget_set_vexpand(image2, TRUE);

    GtkWidget *scroll2=gtk_scrolled_window_new(NULL, NULL);
    gtk_container_add(GTK_CONTAINER(scroll2), image2);
    gpointer data2[]={image2, pixbuf2};
    g_signal_connect(scroll2, "size-allocate", G_CALLBACK(resize_image2), data2);
   
    GtkWidget *grid2=gtk_grid_new();
    gtk_grid_attach(GTK_GRID(grid2), scroll2, 0, 0, 1, 1);

    GtkWidget *nb_label1=gtk_label_new("Page 1");
    GtkWidget *nb_label2=gtk_label_new("Page 2");
    GtkWidget *notebook=gtk_notebook_new();
    gtk_container_set_border_width(GTK_CONTAINER(notebook), 15);
    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), grid1, nb_label1);
    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), grid2, nb_label2);

    gtk_container_add(GTK_CONTAINER(window), notebook);

    gtk_widget_show_all(window);

    gtk_main();

    g_object_unref(pixbuf1);
    g_object_unref(pixbuf2);

    return 0;
  }




_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list