Browse Source

Switch preview rendering to cairo

Martijn Braam 4 years ago
parent
commit
70519058e6
2 changed files with 390 additions and 61 deletions
  1. 332 52
      camera.glade
  2. 58 9
      main.c

+ 332 - 52
camera.glade

@@ -1,32 +1,28 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.1 -->
+<!-- Generated with glade 3.37.0 -->
 <interface>
   <requires lib="gtk+" version="3.20"/>
   <object class="GtkWindow" id="window">
-    <property name="can_focus">False</property>
+    <property name="can-focus">False</property>
     <property name="title" translatable="yes">Camera</property>
-    <child>
-      <placeholder/>
-    </child>
     <child>
       <object class="GtkStack" id="main_stack">
         <property name="visible">True</property>
-        <property name="can_focus">False</property>
+        <property name="can-focus">False</property>
         <child>
-          <object class="GtkBox">
+          <object class="GtkBox" id="page_main">
             <property name="visible">True</property>
-            <property name="can_focus">False</property>
+            <property name="can-focus">False</property>
             <property name="orientation">vertical</property>
             <child>
-              <object class="GtkBox" id="preview_box">
+              <object class="GtkBox">
                 <property name="visible">True</property>
-                <property name="can_focus">False</property>
+                <property name="can-focus">False</property>
                 <property name="orientation">vertical</property>
                 <child>
-                  <object class="GtkImage" id="preview">
+                  <object class="GtkDrawingArea" id="preview">
                     <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="stock">gtk-missing-image</property>
+                    <property name="can-focus">False</property>
                   </object>
                   <packing>
                     <property name="expand">True</property>
@@ -47,23 +43,49 @@
             <child>
               <object class="GtkBox" id="controls_box">
                 <property name="visible">True</property>
-                <property name="can_focus">False</property>
+                <property name="can-focus">False</property>
+                <child type="center">
+                  <object class="GtkButton" id="shutter">
+                    <property name="width-request">48</property>
+                    <property name="height-request">48</property>
+                    <property name="visible">True</property>
+                    <property name="can-focus">True</property>
+                    <property name="receives-default">True</property>
+                    <property name="always-show-image">True</property>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">True</property>
+                        <property name="can-focus">False</property>
+                        <property name="stock">gtk-cdrom</property>
+                      </object>
+                    </child>
+                    <style>
+                      <class name="suggested-action"/>
+                      <class name="circular"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
                 <child>
                   <object class="GtkBox">
                     <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="margin_top">8</property>
-                    <property name="margin_bottom">8</property>
+                    <property name="can-focus">False</property>
+                    <property name="margin-top">8</property>
+                    <property name="margin-bottom">8</property>
                     <property name="spacing">10</property>
                     <child>
-                      <object class="GtkButton">
+                      <object class="GtkButton" id="settings">
                         <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="receives_default">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
                         <child>
                           <object class="GtkImage">
                             <property name="visible">True</property>
-                            <property name="can_focus">False</property>
+                            <property name="can-focus">False</property>
                             <property name="stock">gtk-preferences</property>
                           </object>
                         </child>
@@ -75,7 +97,23 @@
                       </packing>
                     </child>
                     <child>
-                      <placeholder/>
+                      <object class="GtkButton" id="switch_camera">
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="visible">True</property>
+                            <property name="can-focus">False</property>
+                            <property name="stock">gtk-refresh</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
                     </child>
                     <child>
                       <placeholder/>
@@ -88,38 +126,12 @@
                     <property name="position">0</property>
                   </packing>
                 </child>
-                <child type="center">
-                  <object class="GtkButton" id="shutter">
-                    <property name="width_request">48</property>
-                    <property name="height_request">48</property>
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">True</property>
-                    <property name="always_show_image">True</property>
-                    <child>
-                      <object class="GtkImage">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="stock">gtk-cdrom</property>
-                      </object>
-                    </child>
-                    <style>
-                      <class name="suggested-action"/>
-                      <class name="circular"/>
-                    </style>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">2</property>
-                  </packing>
-                </child>
                 <child>
                   <object class="GtkBox">
                     <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="margin_top">8</property>
-                    <property name="margin_bottom">8</property>
+                    <property name="can-focus">False</property>
+                    <property name="margin-top">8</property>
+                    <property name="margin-bottom">8</property>
                     <property name="spacing">10</property>
                     <child>
                       <placeholder/>
@@ -135,7 +147,7 @@
                     <property name="expand">True</property>
                     <property name="fill">True</property>
                     <property name="padding">10</property>
-                    <property name="pack_type">end</property>
+                    <property name="pack-type">end</property>
                     <property name="position">1</property>
                   </packing>
                 </child>
@@ -153,6 +165,274 @@
             <property name="title" translatable="yes">page0</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkScrolledWindow" id="page_settings">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="shadow-type">in</property>
+            <child>
+              <object class="GtkViewport">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <property name="shadow-type">none</property>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="can-focus">False</property>
+                    <property name="margin-start">10</property>
+                    <property name="margin-end">10</property>
+                    <property name="margin-top">10</property>
+                    <property name="margin-bottom">10</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">10</property>
+                    <child>
+                      <object class="GtkBox">
+                        <property name="visible">True</property>
+                        <property name="can-focus">False</property>
+                        <property name="orientation">vertical</property>
+                        <property name="spacing">4</property>
+                        <child>
+                          <object class="GtkLabel">
+                            <property name="visible">True</property>
+                            <property name="can-focus">False</property>
+                            <property name="halign">start</property>
+                            <property name="label" translatable="yes">Photos</property>
+                            <style>
+                              <class name="heading"/>
+                            </style>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkFrame">
+                            <property name="visible">True</property>
+                            <property name="can-focus">False</property>
+                            <property name="label-xalign">0</property>
+                            <property name="shadow-type">in</property>
+                            <child>
+                              <object class="GtkAlignment">
+                                <property name="visible">True</property>
+                                <property name="can-focus">False</property>
+                                <property name="left-padding">12</property>
+                                <child>
+                                  <object class="GtkBox">
+                                    <property name="visible">True</property>
+                                    <property name="can-focus">False</property>
+                                    <property name="orientation">vertical</property>
+                                    <property name="spacing">6</property>
+                                    <child>
+                                      <object class="GtkLabel">
+                                        <property name="visible">True</property>
+                                        <property name="can-focus">False</property>
+                                        <property name="halign">start</property>
+                                        <property name="label" translatable="yes">Resolution</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="position">0</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkComboBox">
+                                        <property name="visible">True</property>
+                                        <property name="can-focus">False</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="position">1</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel">
+                                        <property name="visible">True</property>
+                                        <property name="can-focus">False</property>
+                                        <property name="halign">start</property>
+                                        <property name="label" translatable="yes">Preview mode</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="position">2</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkBox">
+                                        <property name="visible">True</property>
+                                        <property name="can-focus">False</property>
+                                        <property name="orientation">vertical</property>
+                                        <child>
+                                          <object class="GtkRadioButton" id="preview_simple">
+                                            <property name="label" translatable="yes">Full resolution (slowest)</property>
+                                            <property name="visible">True</property>
+                                            <property name="can-focus">True</property>
+                                            <property name="receives-default">False</property>
+                                            <property name="active">True</property>
+                                            <property name="draw-indicator">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">True</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkRadioButton" id="preview_downsample">
+                                            <property name="label" translatable="yes">Quarter resolution debayered</property>
+                                            <property name="visible">True</property>
+                                            <property name="can-focus">True</property>
+                                            <property name="receives-default">False</property>
+                                            <property name="active">True</property>
+                                            <property name="draw-indicator">True</property>
+                                            <property name="group">preview_simple</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">True</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkRadioButton" id="preview_grayscale">
+                                            <property name="label" translatable="yes">Grayscale</property>
+                                            <property name="visible">True</property>
+                                            <property name="can-focus">True</property>
+                                            <property name="receives-default">False</property>
+                                            <property name="active">True</property>
+                                            <property name="draw-indicator">True</property>
+                                            <property name="group">preview_simple</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">True</property>
+                                            <property name="position">2</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="position">3</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel">
+                                        <property name="visible">True</property>
+                                        <property name="can-focus">False</property>
+                                        <property name="halign">start</property>
+                                        <property name="label" translatable="yes">Storage mode</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="position">4</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkBox">
+                                        <property name="visible">True</property>
+                                        <property name="can-focus">False</property>
+                                        <property name="orientation">vertical</property>
+                                        <child>
+                                          <object class="GtkRadioButton" id="store_vng">
+                                            <property name="label" translatable="yes">Debayer with VNG (slowest)</property>
+                                            <property name="visible">True</property>
+                                            <property name="can-focus">True</property>
+                                            <property name="receives-default">False</property>
+                                            <property name="active">True</property>
+                                            <property name="draw-indicator">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">True</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkRadioButton" id="store_simple">
+                                            <property name="label" translatable="yes">Debayer with linear interpolation</property>
+                                            <property name="visible">True</property>
+                                            <property name="can-focus">True</property>
+                                            <property name="receives-default">False</property>
+                                            <property name="active">True</property>
+                                            <property name="draw-indicator">True</property>
+                                            <property name="group">store_vng</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">True</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkRadioButton" id="store_raw">
+                                            <property name="label" translatable="yes">Raw</property>
+                                            <property name="visible">True</property>
+                                            <property name="can-focus">True</property>
+                                            <property name="receives-default">False</property>
+                                            <property name="active">True</property>
+                                            <property name="draw-indicator">True</property>
+                                            <property name="group">store_vng</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">True</property>
+                                            <property name="position">2</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="position">5</property>
+                                      </packing>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child type="label_item">
+                              <placeholder/>
+                            </child>
+                            <style>
+                              <class name="view"/>
+                            </style>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="name">page1</property>
+            <property name="title" translatable="yes">page1</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
       </object>
     </child>
   </object>

+ 58 - 9
main.c

@@ -62,8 +62,12 @@ static int current_height = -1;
 static int current_fmt = 0;
 static int current_rotate = 0;
 static int capture = 0;
+static cairo_surface_t *surface = NULL;
+static int preview_width = -1;
+static int preview_height = -1;
 
-GObject *preview_image;
+// Widgets
+GObject *preview;
 
 static int
 xioctl(int fd, int request, void *arg)
@@ -142,7 +146,7 @@ init_mmap(int fd)
 	if (xioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
 		if (errno == EINVAL) {
 			fprintf(stderr, "%s does not support memory mapping",
-				dev_name);
+				*dev_name);
 			exit(EXIT_FAILURE);
 		} else {
 			errno_exit("VIDIOC_REQBUFS");
@@ -151,7 +155,7 @@ init_mmap(int fd)
 
 	if (req.count < 2) {
 		fprintf(stderr, "Insufficient buffer memory on %s\n",
-			dev_name);
+			*dev_name);
 		exit(EXIT_FAILURE);
 	}
 
@@ -219,7 +223,7 @@ init_device(int fd)
 	if (xioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) {
 		if (errno == EINVAL) {
 			fprintf(stderr, "%s is no V4L2 device\n",
-				dev_name);
+				*dev_name);
 			exit(EXIT_FAILURE);
 		} else {
 			errno_exit("VIDIOC_QUERYCAP");
@@ -228,7 +232,7 @@ init_device(int fd)
 
 	if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
 		fprintf(stderr, "%s is no video capture device\n",
-			dev_name);
+			*dev_name);
 		exit(EXIT_FAILURE);
 	}
 
@@ -236,7 +240,7 @@ init_device(int fd)
 		case IO_METHOD_READ:
 			if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
 				fprintf(stderr, "%s does not support read i/o\n",
-					dev_name);
+					*dev_name);
 				exit(EXIT_FAILURE);
 			}
 			break;
@@ -244,7 +248,7 @@ init_device(int fd)
 		case IO_METHOD_USERPTR:
 			if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
 				fprintf(stderr, "%s does not support streaming i/o\n",
-					dev_name);
+					*dev_name);
 				exit(EXIT_FAILURE);
 			}
 			break;
@@ -346,6 +350,8 @@ process_image(const int *p, int size)
 	GdkPixbuf *pixbuf;
 	GdkPixbuf *pixbufrot;
 	GError *error = NULL;
+	double scale;
+	cairo_t *cr;
 	t = clock();
 
 	dc1394bayer_method_t method = DC1394_BAYER_METHOD_DOWNSAMPLE;
@@ -380,7 +386,15 @@ process_image(const int *p, int size)
 			g_clear_error(&error);
 		}
 	} else {
-		gtk_image_set_from_pixbuf(preview_image, pixbufrot);
+		scale = (double)preview_width/gdk_pixbuf_get_width(pixbufrot);
+		cr = cairo_create(surface);
+		cairo_set_source_rgb(cr, 0,0,0);
+		cairo_paint(cr);
+		gdk_cairo_set_source_pixbuf(cr, pixbufrot, 0, 0);
+		cairo_scale(cr, scale, scale);
+		cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_NONE);
+		cairo_paint(cr);
+		gtk_widget_queue_draw_area(preview, 0, 0, preview_width, preview_height);
 	}
 	capture = 0;
 	t = clock() - t;
@@ -388,6 +402,37 @@ process_image(const int *p, int size)
 	printf("%f fps\n", 1.0/time_taken);
 }
 
+static gboolean
+preview_draw (GtkWidget *widget, cairo_t *cr, gpointer data)
+{
+	cairo_set_source_surface(cr, surface, 0,0);
+	cairo_paint(cr);
+	return FALSE;
+}
+
+static gboolean
+preview_configure (GtkWidget *widget, GdkEventConfigure *event)
+{
+	cairo_t *cr;
+
+	if (surface)
+		cairo_surface_destroy(surface);
+	
+	surface = gdk_window_create_similar_surface (gtk_widget_get_window(widget),
+						     CAIRO_CONTENT_COLOR,
+						     gtk_widget_get_allocated_width (widget),
+						     gtk_widget_get_allocated_height (widget));
+
+	preview_width = gtk_widget_get_allocated_width(widget);
+	preview_height = gtk_widget_get_allocated_height(widget);
+
+	cr = cairo_create(surface);
+	cairo_set_source_rgb(cr, 0, 0, 0);
+	cairo_paint(cr);
+	cairo_destroy(cr);
+	return TRUE;
+}
+
 static int
 read_frame(int fd)
 {
@@ -786,6 +831,7 @@ main(int argc, char *argv[])
 
 	GError *error = NULL;
 	gtk_init(&argc, &argv);
+	g_object_set(gtk_settings_get_default(), "gtk-application-prefer-dark-theme", TRUE, NULL);
 	GtkBuilder *builder = gtk_builder_new();
 	char *glade_file = "/usr/share/camera/ui/camera.glade";
 	if (access("camera.glade", F_OK) != -1) {
@@ -800,9 +846,12 @@ main(int argc, char *argv[])
 	GObject *window = gtk_builder_get_object(builder, "window");
 	GObject *preview_box = gtk_builder_get_object(builder, "preview_box");
 	GObject *shutter = gtk_builder_get_object(builder, "shutter");
-	preview_image = gtk_builder_get_object(builder, "preview");
+	GObject *settings_btn = gtk_builder_get_object(builder, "settings");
+	preview = gtk_builder_get_object(builder, "preview");
 	g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
 	g_signal_connect(shutter, "clicked", G_CALLBACK(on_shutter_clicked), NULL);
+	g_signal_connect(preview, "draw", G_CALLBACK(preview_draw), NULL);
+	g_signal_connect(preview, "configure-event", G_CALLBACK(preview_configure), NULL);
 
 	GtkCssProvider *provider = gtk_css_provider_new();
 	if (access("camera.css", F_OK) != -1) {